OpenCoverage

qopenglframebufferobject.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/gui/opengl/qopenglframebufferobject.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2016 The Qt Company Ltd.-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtGui module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40#include "qopenglframebufferobject.h"-
41#include "qopenglframebufferobject_p.h"-
42-
43#include <qdebug.h>-
44#include <private/qopengl_p.h>-
45#include <private/qopenglcontext_p.h>-
46#include <private/qopenglextensions_p.h>-
47#include <private/qfont_p.h>-
48-
49#include <qwindow.h>-
50#include <qlibrary.h>-
51#include <qimage.h>-
52#include <QtCore/qbytearray.h>-
53-
54QT_BEGIN_NAMESPACE-
55-
56#ifndef QT_NO_DEBUG-
57#define QT_RESET_GLERROR() \-
58{ \-
59 while (QOpenGLContext::currentContext()->functions()->glGetError() != GL_NO_ERROR) {} \-
60}-
61#define QT_CHECK_GLERROR() \-
62{ \-
63 GLenum err = QOpenGLContext::currentContext()->functions()->glGetError(); \-
64 if (err != GL_NO_ERROR) { \-
65 qDebug("[%s line %d] OpenGL Error: %d", \-
66 __FILE__, __LINE__, (int)err); \-
67 } \-
68}-
69#else-
70#define QT_RESET_GLERROR() {}-
71#define QT_CHECK_GLERROR() {}-
72#endif-
73-
74#ifndef GL_MAX_SAMPLES-
75#define GL_MAX_SAMPLES 0x8D57-
76#endif-
77-
78#ifndef GL_RENDERBUFFER_SAMPLES-
79#define GL_RENDERBUFFER_SAMPLES 0x8CAB-
80#endif-
81-
82#ifndef GL_DEPTH24_STENCIL8-
83#define GL_DEPTH24_STENCIL8 0x88F0-
84#endif-
85-
86#ifndef GL_DEPTH_COMPONENT24-
87#define GL_DEPTH_COMPONENT24 0x81A6-
88#endif-
89-
90#ifndef GL_DEPTH_COMPONENT24_OES-
91#define GL_DEPTH_COMPONENT24_OES 0x81A6-
92#endif-
93-
94#ifndef GL_READ_FRAMEBUFFER-
95#define GL_READ_FRAMEBUFFER 0x8CA8-
96#endif-
97-
98#ifndef GL_DRAW_FRAMEBUFFER-
99#define GL_DRAW_FRAMEBUFFER 0x8CA9-
100#endif-
101-
102#ifndef GL_RGB8-
103#define GL_RGB8 0x8051-
104#endif-
105-
106#ifndef GL_RGB10-
107#define GL_RGB10 0x8052-
108#endif-
109-
110#ifndef GL_RGBA8-
111#define GL_RGBA8 0x8058-
112#endif-
113-
114#ifndef GL_RGB10_A2-
115#define GL_RGB10_A2 0x8059-
116#endif-
117-
118#ifndef GL_BGRA-
119#define GL_BGRA 0x80E1-
120#endif-
121-
122#ifndef GL_UNSIGNED_INT_8_8_8_8_REV-
123#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367-
124#endif-
125-
126#ifndef GL_UNSIGNED_INT_2_10_10_10_REV-
127#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368-
128#endif-
129-
130-
131/*!-
132 \class QOpenGLFramebufferObjectFormat-
133 \brief The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL-
134 framebuffer object.-
135 \inmodule QtGui-
136-
137 \since 5.0-
138-
139 \ingroup painting-3D-
140-
141 A framebuffer object has several characteristics:-
142 \list-
143 \li \l{setSamples()}{Number of samples per pixels.}-
144 \li \l{setAttachment()}{Depth and/or stencil attachments.}-
145 \li \l{setTextureTarget()}{Texture target.}-
146 \li \l{setInternalTextureFormat()}{Internal texture format.}-
147 \endlist-
148-
149 Note that the desired attachments or number of samples per pixels might not-
150 be supported by the hardware driver. Call QOpenGLFramebufferObject::format()-
151 after creating a QOpenGLFramebufferObject to find the exact format that was-
152 used to create the frame buffer object.-
153-
154 \sa QOpenGLFramebufferObject-
155*/-
156-
157/*!-
158 \internal-
159*/-
160void QOpenGLFramebufferObjectFormat::detach()-
161{-
162 if (d->ref.load() != 1) {
d->ref.load() != 1Description
TRUEnever evaluated
FALSEnever evaluated
0
163 QOpenGLFramebufferObjectFormatPrivate *newd-
164 = new QOpenGLFramebufferObjectFormatPrivate(d);-
165 if (!d->ref.deref())
!d->ref.deref()Description
TRUEnever evaluated
FALSEnever evaluated
0
166 delete d;
never executed: delete d;
0
167 d = newd;-
168 }
never executed: end of block
0
169}
never executed: end of block
0
170-
171/*!-
172 Creates a QOpenGLFramebufferObjectFormat object for specifying-
173 the format of an OpenGL framebuffer object.-
174-
175 By default the format specifies a non-multisample framebuffer object with no-
176 depth/stencil attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.-
177 On OpenGL/ES systems, the default internal format is \c GL_RGBA.-
178-
179 \sa samples(), attachment(), internalTextureFormat()-
180*/-
181-
182QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat()-
183{-
184 d = new QOpenGLFramebufferObjectFormatPrivate;-
185}
never executed: end of block
0
186-
187/*!-
188 Constructs a copy of \a other.-
189*/-
190-
191QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other)-
192{-
193 d = other.d;-
194 d->ref.ref();-
195}
never executed: end of block
0
196-
197/*!-
198 Assigns \a other to this object.-
199*/-
200-
201QOpenGLFramebufferObjectFormat &QOpenGLFramebufferObjectFormat::operator=(const QOpenGLFramebufferObjectFormat &other)-
202{-
203 if (d != other.d) {
d != other.dDescription
TRUEnever evaluated
FALSEnever evaluated
0
204 other.d->ref.ref();-
205 if (!d->ref.deref())
!d->ref.deref()Description
TRUEnever evaluated
FALSEnever evaluated
0
206 delete d;
never executed: delete d;
0
207 d = other.d;-
208 }
never executed: end of block
0
209 return *this;
never executed: return *this;
0
210}-
211-
212/*!-
213 Destroys the QOpenGLFramebufferObjectFormat.-
214*/-
215QOpenGLFramebufferObjectFormat::~QOpenGLFramebufferObjectFormat()-
216{-
217 if (!d->ref.deref())
!d->ref.deref()Description
TRUEnever evaluated
FALSEnever evaluated
0
218 delete d;
never executed: delete d;
0
219}
never executed: end of block
0
220-
221/*!-
222 Sets the number of samples per pixel for a multisample framebuffer object-
223 to \a samples. The default sample count of 0 represents a regular-
224 non-multisample framebuffer object.-
225-
226 If the desired amount of samples per pixel is not supported by the hardware-
227 then the maximum number of samples per pixel will be used. Note that-
228 multisample framebuffer objects can not be bound as textures. Also, the-
229 \c{GL_EXT_framebuffer_multisample} extension is required to create a-
230 framebuffer with more than one sample per pixel.-
231-
232 \sa samples()-
233*/-
234void QOpenGLFramebufferObjectFormat::setSamples(int samples)-
235{-
236 detach();-
237 d->samples = samples;-
238}
never executed: end of block
0
239-
240/*!-
241 Returns the number of samples per pixel if a framebuffer object-
242 is a multisample framebuffer object. Otherwise, returns 0.-
243 The default value is 0.-
244-
245 \sa setSamples()-
246*/-
247int QOpenGLFramebufferObjectFormat::samples() const-
248{-
249 return d->samples;
never executed: return d->samples;
0
250}-
251-
252/*!-
253 Enables mipmapping if \a enabled is true; otherwise disables it.-
254-
255 Mipmapping is disabled by default.-
256-
257 If mipmapping is enabled, additional memory will be allocated for-
258 the mipmap levels. The mipmap levels can be updated by binding the-
259 texture and calling glGenerateMipmap(). Mipmapping cannot be enabled-
260 for multisampled framebuffer objects.-
261-
262 \sa mipmap(), QOpenGLFramebufferObject::texture()-
263*/-
264void QOpenGLFramebufferObjectFormat::setMipmap(bool enabled)-
265{-
266 detach();-
267 d->mipmap = enabled;-
268}
never executed: end of block
0
269-
270/*!-
271 Returns \c true if mipmapping is enabled.-
272-
273 \sa setMipmap()-
274*/-
275bool QOpenGLFramebufferObjectFormat::mipmap() const-
276{-
277 return d->mipmap;
never executed: return d->mipmap;
0
278}-
279-
280/*!-
281 Sets the attachment configuration of a framebuffer object to \a attachment.-
282-
283 \sa attachment()-
284*/-
285void QOpenGLFramebufferObjectFormat::setAttachment(QOpenGLFramebufferObject::Attachment attachment)-
286{-
287 detach();-
288 d->attachment = attachment;-
289}
never executed: end of block
0
290-
291/*!-
292 Returns the configuration of the depth and stencil buffers attached to-
293 a framebuffer object. The default is QOpenGLFramebufferObject::NoAttachment.-
294-
295 \sa setAttachment()-
296*/-
297QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObjectFormat::attachment() const-
298{-
299 return d->attachment;
never executed: return d->attachment;
0
300}-
301-
302/*!-
303 Sets the texture target of the texture attached to a framebuffer object to-
304 \a target. Ignored for multisample framebuffer objects.-
305-
306 \sa textureTarget(), samples()-
307*/-
308void QOpenGLFramebufferObjectFormat::setTextureTarget(GLenum target)-
309{-
310 detach();-
311 d->target = target;-
312}
never executed: end of block
0
313-
314/*!-
315 Returns the texture target of the texture attached to a framebuffer object.-
316 Ignored for multisample framebuffer objects. The default is-
317 \c GL_TEXTURE_2D.-
318-
319 \sa setTextureTarget(), samples()-
320*/-
321GLenum QOpenGLFramebufferObjectFormat::textureTarget() const-
322{-
323 return d->target;
never executed: return d->target;
0
324}-
325-
326/*!-
327 Sets the internal format of a framebuffer object's texture or-
328 multisample framebuffer object's color buffer to-
329 \a internalTextureFormat.-
330-
331 \sa internalTextureFormat()-
332*/-
333void QOpenGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)-
334{-
335 detach();-
336 d->internal_format = internalTextureFormat;-
337}
never executed: end of block
0
338-
339/*!-
340 Returns the internal format of a framebuffer object's texture or-
341 multisample framebuffer object's color buffer. The default is-
342 \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on-
343 OpenGL/ES systems.-
344-
345 \sa setInternalTextureFormat()-
346*/-
347GLenum QOpenGLFramebufferObjectFormat::internalTextureFormat() const-
348{-
349 return d->internal_format;
never executed: return d->internal_format;
0
350}-
351-
352/*!-
353 Returns \c true if all the options of this framebuffer object format-
354 are the same as \a other; otherwise returns \c false.-
355*/-
356bool QOpenGLFramebufferObjectFormat::operator==(const QOpenGLFramebufferObjectFormat& other) const-
357{-
358 if (d == other.d)
d == other.dDescription
TRUEnever evaluated
FALSEnever evaluated
0
359 return true;
never executed: return true;
0
360 else-
361 return d->equals(other.d);
never executed: return d->equals(other.d);
0
362}-
363-
364/*!-
365 Returns \c false if all the options of this framebuffer object format-
366 are the same as \a other; otherwise returns \c true.-
367*/-
368bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFormat& other) const-
369{-
370 return !(*this == other);
never executed: return !(*this == other);
0
371}-
372-
373bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus(QOpenGLContext *ctx) const-
374{-
375 if (!ctx)
!ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
376 return false; // Context no longer exists.
never executed: return false;
0
377 GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);-
378 switch(status) {-
379 case GL_NO_ERROR:
never executed: case 0:
0
380 case GL_FRAMEBUFFER_COMPLETE:
never executed: case 0x8CD5:
0
381 return true;
never executed: return true;
0
382 case GL_FRAMEBUFFER_UNSUPPORTED:
never executed: case 0x8CDD:
0
383 qDebug("QOpenGLFramebufferObject: Unsupported framebuffer format.");-
384 break;
never executed: break;
0
385 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
never executed: case 0x8CD6:
0
386 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete attachment.");-
387 break;
never executed: break;
0
388 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
never executed: case 0x8CD7:
0
389 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment.");-
390 break;
never executed: break;
0
391#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT-
392 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT:-
393 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");-
394 break;-
395#endif-
396#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS-
397 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:-
398 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");-
399 break;-
400#endif-
401#ifdef GL_FRAMEBUFFER_INCOMPLETE_FORMATS-
402 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:-
403 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");-
404 break;-
405#endif-
406#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER-
407 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
never executed: case 0x8CDB:
0
408 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");-
409 break;
never executed: break;
0
410#endif-
411#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER-
412 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
never executed: case 0x8CDC:
0
413 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing read buffer.");-
414 break;
never executed: break;
0
415#endif-
416#ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE-
417 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
never executed: case 0x8D56:
0
418 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");-
419 break;
never executed: break;
0
420#endif-
421 default:
never executed: default:
0
422 qDebug() <<"QOpenGLFramebufferObject: An undefined error has occurred: "<< status;-
423 break;
never executed: break;
0
424 }-
425 return false;
never executed: return false;
0
426}-
427-
428namespace-
429{-
430 void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)-
431 {-
432 funcs->glDeleteFramebuffers(1, &id);-
433 }
never executed: end of block
0
434-
435 void freeRenderbufferFunc(QOpenGLFunctions *funcs, GLuint id)-
436 {-
437 funcs->glDeleteRenderbuffers(1, &id);-
438 }
never executed: end of block
0
439-
440 void freeTextureFunc(QOpenGLFunctions *funcs, GLuint id)-
441 {-
442 funcs->glDeleteTextures(1, &id);-
443 }
never executed: end of block
0
444}-
445-
446void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSize &size,-
447 QOpenGLFramebufferObject::Attachment attachment,-
448 GLenum texture_target, GLenum internal_format,-
449 GLint samples, bool mipmap)-
450{-
451 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
452-
453 funcs.initializeOpenGLFunctions();-
454-
455 if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers))
!funcs.hasOpen...:Framebuffers)Description
TRUEnever evaluated
FALSEnever evaluated
0
456 return;
never executed: return;
0
457-
458 // Fall back to using a normal non-msaa FBO if we don't have support for MSAA-
459 if (!funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
!funcs.hasOpen...erMultisample)Description
TRUEnever evaluated
FALSEnever evaluated
0
460 || !funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) {
!funcs.hasOpen...amebufferBlit)Description
TRUEnever evaluated
FALSEnever evaluated
0
461 samples = 0;-
462 } else if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
never executed: end of block
!ctx->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
ctx->format()....Version() >= 3Description
TRUEnever evaluated
FALSEnever evaluated
0
463 GLint maxSamples;-
464 funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);-
465 samples = qBound(0, int(samples), int(maxSamples));-
466 }
never executed: end of block
0
467-
468 colorAttachments.append(ColorAttachment(size, internal_format));-
469-
470 dsSize = size;-
471-
472 samples = qMax(0, samples);-
473 requestedSamples = samples;-
474-
475 target = texture_target;-
476-
477 QT_RESET_GLERROR(); // reset error state
never executed: end of block
QOpenGLContext...etError() != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
478 GLuint fbo = 0;-
479-
480 funcs.glGenFramebuffers(1, &fbo);-
481 funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo);-
482-
483 QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true;-
484-
485 QT_CHECK_GLERROR();
never executed: end of block
err != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
486-
487 format.setTextureTarget(target);-
488 format.setInternalTextureFormat(internal_format);-
489 format.setMipmap(mipmap);-
490-
491 if (samples == 0)
samples == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
492 initTexture(0);
never executed: initTexture(0);
0
493 else-
494 initColorBuffer(0, &samples);
never executed: initColorBuffer(0, &samples);
0
495-
496 format.setSamples(int(samples));-
497-
498 initDepthStencilAttachments(ctx, attachment);-
499-
500 if (valid)
validDescription
TRUEnever evaluated
FALSEnever evaluated
0
501 fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
never executed: fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
0
502 else-
503 funcs.glDeleteFramebuffers(1, &fbo);
never executed: funcs.glDeleteFramebuffers(1, &fbo);
0
504-
505 QT_CHECK_GLERROR();
never executed: end of block
err != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
506}
never executed: end of block
0
507-
508void QOpenGLFramebufferObjectPrivate::initTexture(int idx)-
509{-
510 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
511 GLuint texture = 0;-
512-
513 funcs.glGenTextures(1, &texture);-
514 funcs.glBindTexture(target, texture);-
515-
516 funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);-
517 funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);-
518 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);-
519 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);-
520-
521 ColorAttachment &color(colorAttachments[idx]);-
522-
523 GLuint pixelType = GL_UNSIGNED_BYTE;-
524 if (color.internalFormat == GL_RGB10_A2 || color.internalFormat == GL_RGB10)
color.internalFormat == 0x8059Description
TRUEnever evaluated
FALSEnever evaluated
color.internalFormat == 0x8052Description
TRUEnever evaluated
FALSEnever evaluated
0
525 pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
never executed: pixelType = 0x8368;
0
526-
527 funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,-
528 GL_RGBA, pixelType, NULL);-
529 if (format.mipmap()) {
format.mipmap()Description
TRUEnever evaluated
FALSEnever evaluated
0
530 int width = color.size.width();-
531 int height = color.size.height();-
532 int level = 0;-
533 while (width > 1 || height > 1) {
width > 1Description
TRUEnever evaluated
FALSEnever evaluated
height > 1Description
TRUEnever evaluated
FALSEnever evaluated
0
534 width = qMax(1, width >> 1);-
535 height = qMax(1, height >> 1);-
536 ++level;-
537 funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0,-
538 GL_RGBA, pixelType, NULL);-
539 }
never executed: end of block
0
540 }
never executed: end of block
0
541 funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx,-
542 target, texture, 0);-
543-
544 QT_CHECK_GLERROR();
never executed: end of block
err != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
545 funcs.glBindTexture(target, 0);-
546 valid = checkFramebufferStatus(ctx);-
547 if (valid) {
validDescription
TRUEnever evaluated
FALSEnever evaluated
0
548 color.guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);-
549 } else {
never executed: end of block
0
550 funcs.glDeleteTextures(1, &texture);-
551 }
never executed: end of block
0
552}-
553-
554void QOpenGLFramebufferObjectPrivate::initColorBuffer(int idx, GLint *samples)-
555{-
556 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
557 GLuint color_buffer = 0;-
558-
559 ColorAttachment &color(colorAttachments[idx]);-
560-
561 GLenum storageFormat = color.internalFormat;-
562 // ES requires a sized format. The older desktop extension does not. Correct the format on ES.-
563 if (ctx->isOpenGLES() && color.internalFormat == GL_RGBA) {
ctx->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
color.internalFormat == 0x1908Description
TRUEnever evaluated
FALSEnever evaluated
0
564 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Sized8Formats))
funcs.hasOpenG...Sized8Formats)Description
TRUEnever evaluated
FALSEnever evaluated
0
565 storageFormat = GL_RGBA8;
never executed: storageFormat = 0x8058;
0
566 else-
567 storageFormat = GL_RGBA4;
never executed: storageFormat = 0x8056;
0
568 }-
569-
570 funcs.glGenRenderbuffers(1, &color_buffer);-
571 funcs.glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);-
572 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, *samples, storageFormat, color.size.width(), color.size.height());-
573 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx,-
574 GL_RENDERBUFFER, color_buffer);-
575-
576 QT_CHECK_GLERROR();
never executed: end of block
err != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
577 valid = checkFramebufferStatus(ctx);-
578 if (valid) {
validDescription
TRUEnever evaluated
FALSEnever evaluated
0
579 // Query the actual number of samples. This can be greater than the requested-
580 // value since the typically supported values are 0, 4, 8, ..., and the-
581 // requests are mapped to the next supported value.-
582 funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, samples);-
583 color.guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);-
584 } else {
never executed: end of block
0
585 funcs.glDeleteRenderbuffers(1, &color_buffer);-
586 }
never executed: end of block
0
587}-
588-
589void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext *ctx,-
590 QOpenGLFramebufferObject::Attachment attachment)-
591{-
592 // Use the same sample count for all attachments. format.samples() already contains-
593 // the actual number of samples for the color attachment and is not suitable. Use-
594 // requestedSamples instead.-
595 const int samples = requestedSamples;-
596-
597 // free existing attachments-
598 if (depth_buffer_guard) {
depth_buffer_guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
599 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);-
600 depth_buffer_guard->free();-
601 }
never executed: end of block
0
602 if (stencil_buffer_guard) {
stencil_buffer_guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
603 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);-
604 if (stencil_buffer_guard != depth_buffer_guard)
stencil_buffer...h_buffer_guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
605 stencil_buffer_guard->free();
never executed: stencil_buffer_guard->free();
0
606 }
never executed: end of block
0
607-
608 depth_buffer_guard = 0;-
609 stencil_buffer_guard = 0;-
610-
611 GLuint depth_buffer = 0;-
612 GLuint stencil_buffer = 0;-
613-
614 // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a-
615 // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer-
616 // might not be supported while separate buffers are, according to QTBUG-12861.-
617-
618 if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
attachment == ...edDepthStencilDescription
TRUEnever evaluated
FALSEnever evaluated
0
619 && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
funcs.hasOpenG...dDepthStencil)Description
TRUEnever evaluated
FALSEnever evaluated
0
620 {-
621 // depth and stencil buffer needs another extension-
622 funcs.glGenRenderbuffers(1, &depth_buffer);-
623 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);-
624 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));-
625 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
samples != 0Description
TRUEnever evaluated
FALSEnever evaluated
funcs.hasOpenG...erMultisample)Description
TRUEnever evaluated
FALSEnever evaluated
0
626 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, 0x88F0, dsSize.width(), dsSize.height());
0
627 GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height());
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, 0x88F0, dsSize.width(), dsSize.height());
0
628 else-
629 funcs.glRenderbufferStorage(GL_RENDERBUFFER,
never executed: funcs.glRenderbufferStorage(0x8D41, 0x88F0, dsSize.width(), dsSize.height());
0
630 GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height());
never executed: funcs.glRenderbufferStorage(0x8D41, 0x88F0, dsSize.width(), dsSize.height());
0
631-
632 stencil_buffer = depth_buffer;-
633 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,-
634 GL_RENDERBUFFER, depth_buffer);-
635 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,-
636 GL_RENDERBUFFER, stencil_buffer);-
637-
638 valid = checkFramebufferStatus(ctx);-
639 if (!valid) {
!validDescription
TRUEnever evaluated
FALSEnever evaluated
0
640 funcs.glDeleteRenderbuffers(1, &depth_buffer);-
641 stencil_buffer = depth_buffer = 0;-
642 }
never executed: end of block
0
643 }
never executed: end of block
0
644-
645 if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
depth_buffer == 0Description
TRUEnever evaluated
FALSEnever evaluated
attachment == ...edDepthStencilDescription
TRUEnever evaluated
FALSEnever evaluated
0
646 || (attachment == QOpenGLFramebufferObject::Depth)))
(attachment ==...Object::Depth)Description
TRUEnever evaluated
FALSEnever evaluated
0
647 {-
648 funcs.glGenRenderbuffers(1, &depth_buffer);-
649 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);-
650 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));-
651 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
samples != 0Description
TRUEnever evaluated
FALSEnever evaluated
funcs.hasOpenG...erMultisample)Description
TRUEnever evaluated
FALSEnever evaluated
0
652 if (ctx->isOpenGLES()) {
ctx->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
0
653 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24))
funcs.hasOpenG...ions::Depth24)Description
TRUEnever evaluated
FALSEnever evaluated
0
654 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, 0x81A6, dsSize.width(), dsSize.height());
0
655 GL_DEPTH_COMPONENT24, dsSize.width(), dsSize.height());
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, 0x81A6, dsSize.width(), dsSize.height());
0
656 else-
657 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, 0x81A5, dsSize.width(), dsSize.height());
0
658 GL_DEPTH_COMPONENT16, dsSize.width(), dsSize.height());
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, 0x81A5, dsSize.width(), dsSize.height());
0
659 } else {-
660 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,-
661 GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());-
662 }
never executed: end of block
0
663 } else {-
664 if (ctx->isOpenGLES()) {
ctx->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
0
665 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
funcs.hasOpenG...ions::Depth24)Description
TRUEnever evaluated
FALSEnever evaluated
0
666 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24,-
667 dsSize.width(), dsSize.height());-
668 } else {
never executed: end of block
0
669 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,-
670 dsSize.width(), dsSize.height());-
671 }
never executed: end of block
0
672 } else {-
673 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());-
674 }
never executed: end of block
0
675 }-
676 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,-
677 GL_RENDERBUFFER, depth_buffer);-
678 valid = checkFramebufferStatus(ctx);-
679 if (!valid) {
!validDescription
TRUEnever evaluated
FALSEnever evaluated
0
680 funcs.glDeleteRenderbuffers(1, &depth_buffer);-
681 depth_buffer = 0;-
682 }
never executed: end of block
0
683 }
never executed: end of block
0
684-
685 if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) {
stencil_buffer == 0Description
TRUEnever evaluated
FALSEnever evaluated
(attachment ==...dDepthStencil)Description
TRUEnever evaluated
FALSEnever evaluated
0
686 funcs.glGenRenderbuffers(1, &stencil_buffer);-
687 funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer);-
688 Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer));-
689-
690#ifdef QT_OPENGL_ES-
691 GLenum storage = GL_STENCIL_INDEX8;-
692#else-
693 GLenum storage = ctx->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
ctx->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
0
694#endif-
695-
696 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
samples != 0Description
TRUEnever evaluated
FALSEnever evaluated
funcs.hasOpenG...erMultisample)Description
TRUEnever evaluated
FALSEnever evaluated
0
697 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, dsSize.width(), dsSize.height());
never executed: funcs.glRenderbufferStorageMultisample(0x8D41, samples, storage, dsSize.width(), dsSize.height());
0
698 else-
699 funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, dsSize.width(), dsSize.height());
never executed: funcs.glRenderbufferStorage(0x8D41, storage, dsSize.width(), dsSize.height());
0
700-
701 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,-
702 GL_RENDERBUFFER, stencil_buffer);-
703 valid = checkFramebufferStatus(ctx);-
704 if (!valid) {
!validDescription
TRUEnever evaluated
FALSEnever evaluated
0
705 funcs.glDeleteRenderbuffers(1, &stencil_buffer);-
706 stencil_buffer = 0;-
707 }
never executed: end of block
0
708 }
never executed: end of block
0
709-
710 // The FBO might have become valid after removing the depth or stencil buffer.-
711 valid = checkFramebufferStatus(ctx);-
712-
713 if (depth_buffer && stencil_buffer) {
depth_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
stencil_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
714 fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;-
715 } else if (depth_buffer) {
never executed: end of block
depth_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
716 fbo_attachment = QOpenGLFramebufferObject::Depth;-
717 } else {
never executed: end of block
0
718 fbo_attachment = QOpenGLFramebufferObject::NoAttachment;-
719 }
never executed: end of block
0
720-
721 if (valid) {
validDescription
TRUEnever evaluated
FALSEnever evaluated
0
722 if (depth_buffer)
depth_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
723 depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
never executed: depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
0
724 if (stencil_buffer) {
stencil_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
725 if (stencil_buffer == depth_buffer)
stencil_buffer == depth_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
726 stencil_buffer_guard = depth_buffer_guard;
never executed: stencil_buffer_guard = depth_buffer_guard;
0
727 else-
728 stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
never executed: stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
0
729 }-
730 } else {
never executed: end of block
0
731 if (depth_buffer)
depth_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
732 funcs.glDeleteRenderbuffers(1, &depth_buffer);
never executed: funcs.glDeleteRenderbuffers(1, &depth_buffer);
0
733 if (stencil_buffer && depth_buffer != stencil_buffer)
stencil_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
depth_buffer != stencil_bufferDescription
TRUEnever evaluated
FALSEnever evaluated
0
734 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
never executed: funcs.glDeleteRenderbuffers(1, &stencil_buffer);
0
735 }
never executed: end of block
0
736 QT_CHECK_GLERROR();
never executed: end of block
err != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
737-
738 format.setAttachment(fbo_attachment);-
739}
never executed: end of block
0
740-
741/*!-
742 \class QOpenGLFramebufferObject-
743 \brief The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer object.-
744 \since 5.0-
745 \inmodule QtGui-
746-
747 \ingroup painting-3D-
748-
749 The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer-
750 object, defined by the \c{GL_EXT_framebuffer_object} extension. It provides-
751 a rendering surface that can be painted on with a QPainter with the help of-
752 QOpenGLPaintDevice, or rendered to using native OpenGL calls. This surface-
753 can be bound and used as a regular texture in your own OpenGL drawing code.-
754 By default, the QOpenGLFramebufferObject class generates a 2D OpenGL-
755 texture (using the \c{GL_TEXTURE_2D} target), which is used as the internal-
756 rendering target.-
757-
758 \b{It is important to have a current OpenGL context when creating a-
759 QOpenGLFramebufferObject, otherwise initialization will fail.}-
760-
761 Create the QOpenGLFrameBufferObject instance with the CombinedDepthStencil-
762 attachment if you want QPainter to render correctly. Note that you need to-
763 create a QOpenGLFramebufferObject with more than one sample per pixel for-
764 primitives to be antialiased when drawing using a QPainter. To create a-
765 multisample framebuffer object you should use one of the constructors that-
766 take a QOpenGLFramebufferObjectFormat parameter, and set the-
767 QOpenGLFramebufferObjectFormat::samples() property to a non-zero value.-
768-
769 For multisample framebuffer objects a color render buffer is created,-
770 otherwise a texture with the specified texture target is created.-
771 The color render buffer or texture will have the specified internal-
772 format, and will be bound to the \c GL_COLOR_ATTACHMENT0-
773 attachment in the framebuffer object.-
774-
775 Multiple render targets are also supported, in case the OpenGL-
776 implementation supports this. Here there will be multiple textures (or, in-
777 case of multisampling, renderbuffers) present and each of them will get-
778 attached to \c GL_COLOR_ATTACHMENT0, \c 1, \c 2, ...-
779-
780 If you want to use a framebuffer object with multisampling enabled-
781 as a texture, you first need to copy from it to a regular framebuffer-
782 object using QOpenGLContext::blitFramebuffer().-
783-
784 It is possible to draw into a QOpenGLFramebufferObject using QPainter and-
785 QOpenGLPaintDevice in a separate thread.-
786*/-
787-
788-
789/*!-
790 \enum QOpenGLFramebufferObject::Attachment-
791-
792 This enum type is used to configure the depth and stencil buffers-
793 attached to the framebuffer object when it is created.-
794-
795 \value NoAttachment No attachment is added to the framebuffer object. Note that the-
796 OpenGL depth and stencil tests won't work when rendering to a-
797 framebuffer object without any depth or stencil buffers.-
798 This is the default value.-
799-
800 \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,-
801 a combined depth and stencil buffer is attached.-
802 If the extension is not present, only a depth buffer is attached.-
803-
804 \value Depth A depth buffer is attached to the framebuffer object.-
805-
806 \sa attachment()-
807*/-
808-
809static inline GLenum effectiveInternalFormat(GLenum internalFormat)-
810{-
811 if (!internalFormat)
!internalFormatDescription
TRUEnever evaluated
FALSEnever evaluated
0
812#ifdef QT_OPENGL_ES_2-
813 internalFormat = GL_RGBA;-
814#else-
815 internalFormat = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8;
never executed: internalFormat = QOpenGLContext::currentContext()->isOpenGLES() ? 0x1908 : 0x8058;
QOpenGLContext...->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
0
816#endif-
817 return internalFormat;
never executed: return internalFormat;
0
818}-
819-
820/*! \fn QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target)-
821-
822 Constructs an OpenGL framebuffer object and binds a 2D OpenGL texture-
823 to the buffer of the size \a size. The texture is bound to the-
824 \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.-
825-
826 The \a target parameter is used to specify the OpenGL texture-
827 target. The default target is \c GL_TEXTURE_2D. Keep in mind that-
828 \c GL_TEXTURE_2D textures must have a power of 2 width and height-
829 (e.g. 256x512), unless you are using OpenGL 2.0 or higher.-
830-
831 By default, no depth and stencil buffers are attached. This behavior-
832 can be toggled using one of the overloaded constructors.-
833-
834 The default internal texture format is \c GL_RGBA8 for desktop-
835 OpenGL, and \c GL_RGBA for OpenGL/ES.-
836-
837 It is important that you have a current OpenGL context set when-
838 creating the QOpenGLFramebufferObject, otherwise the initialization-
839 will fail.-
840-
841 \sa size(), texture(), attachment()-
842*/-
843-
844QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target)-
845 : d_ptr(new QOpenGLFramebufferObjectPrivate)-
846{-
847 Q_D(QOpenGLFramebufferObject);-
848 d->init(this, size, NoAttachment, target, effectiveInternalFormat(0));-
849}
never executed: end of block
0
850-
851/*! \overload-
852-
853 Constructs an OpenGL framebuffer object and binds a 2D OpenGL texture-
854 to the buffer of the given \a width and \a height.-
855-
856 \sa size(), texture()-
857*/-
858QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, GLenum target)-
859 : d_ptr(new QOpenGLFramebufferObjectPrivate)-
860{-
861 Q_D(QOpenGLFramebufferObject);-
862 d->init(this, QSize(width, height), NoAttachment, target, effectiveInternalFormat(0));-
863}
never executed: end of block
0
864-
865/*! \overload-
866-
867 Constructs an OpenGL framebuffer object of the given \a size based on the-
868 supplied \a format.-
869*/-
870-
871QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format)-
872 : d_ptr(new QOpenGLFramebufferObjectPrivate)-
873{-
874 Q_D(QOpenGLFramebufferObject);-
875 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),-
876 format.samples(), format.mipmap());-
877}
never executed: end of block
0
878-
879/*! \overload-
880-
881 Constructs an OpenGL framebuffer object of the given \a width and \a height-
882 based on the supplied \a format.-
883*/-
884-
885QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format)-
886 : d_ptr(new QOpenGLFramebufferObjectPrivate)-
887{-
888 Q_D(QOpenGLFramebufferObject);-
889 d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),-
890 format.internalTextureFormat(), format.samples(), format.mipmap());-
891}
never executed: end of block
0
892-
893/*! \overload-
894-
895 Constructs an OpenGL framebuffer object and binds a texture to the-
896 buffer of the given \a width and \a height.-
897-
898 The \a attachment parameter describes the depth/stencil buffer-
899 configuration, \a target the texture target and \a internalFormat-
900 the internal texture format. The default texture target is \c-
901 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8-
902 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.-
903-
904 \sa size(), texture(), attachment()-
905*/-
906QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, Attachment attachment,-
907 GLenum target, GLenum internalFormat)-
908 : d_ptr(new QOpenGLFramebufferObjectPrivate)-
909{-
910 Q_D(QOpenGLFramebufferObject);-
911 d->init(this, QSize(width, height), attachment, target, effectiveInternalFormat(internalFormat));-
912}
never executed: end of block
0
913-
914/*! \overload-
915-
916 Constructs an OpenGL framebuffer object and binds a texture to the-
917 buffer of the given \a size.-
918-
919 The \a attachment parameter describes the depth/stencil buffer-
920 configuration, \a target the texture target and \a internalFormat-
921 the internal texture format. The default texture target is \c-
922 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8-
923 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.-
924-
925 \sa size(), texture(), attachment()-
926*/-
927QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, Attachment attachment,-
928 GLenum target, GLenum internalFormat)-
929 : d_ptr(new QOpenGLFramebufferObjectPrivate)-
930{-
931 Q_D(QOpenGLFramebufferObject);-
932 d->init(this, size, attachment, target, effectiveInternalFormat(internalFormat));-
933}
never executed: end of block
0
934-
935/*!-
936 \fn QOpenGLFramebufferObject::~QOpenGLFramebufferObject()-
937-
938 Destroys the framebuffer object and frees any allocated resources.-
939*/-
940QOpenGLFramebufferObject::~QOpenGLFramebufferObject()-
941{-
942 Q_D(QOpenGLFramebufferObject);-
943 if (isBound())
isBound()Description
TRUEnever evaluated
FALSEnever evaluated
0
944 release();
never executed: release();
0
945-
946 for (const auto &color : qAsConst(d->colorAttachments)) {-
947 if (color.guard)
color.guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
948 color.guard->free();
never executed: color.guard->free();
0
949 }
never executed: end of block
0
950 d->colorAttachments.clear();-
951-
952 if (d->depth_buffer_guard)
d->depth_buffer_guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
953 d->depth_buffer_guard->free();
never executed: d->depth_buffer_guard->free();
0
954 if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
d->stencil_buffer_guardDescription
TRUEnever evaluated
FALSEnever evaluated
d->stencil_buf...h_buffer_guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
955 d->stencil_buffer_guard->free();
never executed: d->stencil_buffer_guard->free();
0
956 if (d->fbo_guard)
d->fbo_guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
957 d->fbo_guard->free();
never executed: d->fbo_guard->free();
0
958-
959 QOpenGLContextPrivate *contextPrv = QOpenGLContextPrivate::get(QOpenGLContext::currentContext());-
960 if (contextPrv && contextPrv->qgl_current_fbo == this) {
contextPrvDescription
TRUEnever evaluated
FALSEnever evaluated
contextPrv->qg...nt_fbo == thisDescription
TRUEnever evaluated
FALSEnever evaluated
0
961 contextPrv->qgl_current_fbo_invalid = true;-
962 contextPrv->qgl_current_fbo = Q_NULLPTR;-
963 }
never executed: end of block
0
964}
never executed: end of block
0
965-
966/*!-
967 Creates and attaches an additional texture or renderbuffer of \a size width-
968 and height.-
969-
970 There is always an attachment at GL_COLOR_ATTACHMENT0. Call this function-
971 to set up additional attachments at GL_COLOR_ATTACHMENT1,-
972 GL_COLOR_ATTACHMENT2, ...-
973-
974 When \a internalFormat is not \c 0, it specifies the internal format of the-
975 texture or renderbuffer. Otherwise a default of GL_RGBA or GL_RGBA8 is-
976 used.-
977-
978 \note This is only functional when multiple render targets are supported by-
979 the OpenGL implementation. When that is not the case, the function will not-
980 add any additional color attachments. Call-
981 QOpenGLFunctions::hasOpenGLFeature() with-
982 QOpenGLFunctions::MultipleRenderTargets at runtime to check if MRT is-
983 supported.-
984-
985 \note The internal format of the color attachments may differ but there may-
986 be limitations on the supported combinations, depending on the drivers.-
987-
988 \note The size of the color attachments may differ but rendering is limited-
989 to the area that fits all the attachments, according to the OpenGL-
990 specification. Some drivers may not be fully conformant in this respect,-
991 however.-
992-
993 \since 5.6-
994 */-
995void QOpenGLFramebufferObject::addColorAttachment(const QSize &size, GLenum internalFormat)-
996{-
997 Q_D(QOpenGLFramebufferObject);-
998-
999 if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
!QOpenGLContex...RenderTargets)Description
TRUEnever evaluated
FALSEnever evaluated
0
1000 qWarning("Multiple render targets not supported, ignoring extra color attachment request");-
1001 return;
never executed: return;
0
1002 }-
1003-
1004 QOpenGLFramebufferObjectPrivate::ColorAttachment color(size, effectiveInternalFormat(internalFormat));-
1005 d->colorAttachments.append(color);-
1006 const int idx = d->colorAttachments.count() - 1;-
1007-
1008 if (d->requestedSamples == 0) {
d->requestedSamples == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1009 d->initTexture(idx);-
1010 } else {
never executed: end of block
0
1011 GLint samples = d->requestedSamples;-
1012 d->initColorBuffer(idx, &samples);-
1013 }
never executed: end of block
0
1014}-
1015-
1016/*! \overload-
1017-
1018 Creates and attaches an additional texture or renderbuffer of size \a width and \a height.-
1019-
1020 When \a internalFormat is not \c 0, it specifies the internal format of the texture or-
1021 renderbuffer. Otherwise a default of GL_RGBA or GL_RGBA8 is used.-
1022-
1023 \since 5.6-
1024 */-
1025void QOpenGLFramebufferObject::addColorAttachment(int width, int height, GLenum internalFormat)-
1026{-
1027 addColorAttachment(QSize(width, height), internalFormat);-
1028}
never executed: end of block
0
1029-
1030/*!-
1031 \fn bool QOpenGLFramebufferObject::isValid() const-
1032-
1033 Returns \c true if the framebuffer object is valid.-
1034-
1035 The framebuffer can become invalid if the initialization process-
1036 fails, the user attaches an invalid buffer to the framebuffer-
1037 object, or a non-power of two width/height is specified as the-
1038 texture size if the texture target is \c{GL_TEXTURE_2D}.-
1039 The non-power of two limitation does not apply if the OpenGL version-
1040 is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension-
1041 is present.-
1042-
1043 The framebuffer can also become invalid if the QOpenGLContext that-
1044 the framebuffer was created within is destroyed and there are-
1045 no other shared contexts that can take over ownership of the-
1046 framebuffer.-
1047*/-
1048bool QOpenGLFramebufferObject::isValid() const-
1049{-
1050 Q_D(const QOpenGLFramebufferObject);-
1051 return d->valid && d->fbo_guard && d->fbo_guard->id();
never executed: return d->valid && d->fbo_guard && d->fbo_guard->id();
0
1052}-
1053-
1054/*!-
1055 \fn bool QOpenGLFramebufferObject::bind()-
1056-
1057 Switches rendering from the default, windowing system provided-
1058 framebuffer to this framebuffer object.-
1059 Returns \c true upon success, false otherwise.-
1060-
1061 \note If takeTexture() was called, a new texture is created and associated-
1062 with the framebuffer object. This is potentially expensive and changes the-
1063 context state (the currently bound texture).-
1064-
1065 \sa release()-
1066*/-
1067bool QOpenGLFramebufferObject::bind()-
1068{-
1069 if (!isValid())
!isValid()Description
TRUEnever evaluated
FALSEnever evaluated
0
1070 return false;
never executed: return false;
0
1071 Q_D(QOpenGLFramebufferObject);-
1072 QOpenGLContext *current = QOpenGLContext::currentContext();-
1073 if (!current)
!currentDescription
TRUEnever evaluated
FALSEnever evaluated
0
1074 return false;
never executed: return false;
0
1075#ifdef QT_DEBUG-
1076 if (current->shareGroup() != d->fbo_guard->group())
current->share...guard->group()Description
TRUEnever evaluated
FALSEnever evaluated
0
1077 qWarning("QOpenGLFramebufferObject::bind() called from incompatible context");
never executed: QMessageLogger(__FILE__, 1077, __PRETTY_FUNCTION__).warning("QOpenGLFramebufferObject::bind() called from incompatible context");
0
1078#endif-
1079-
1080 d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());-
1081-
1082 QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true;-
1083 QOpenGLContextPrivate::get(current)->qgl_current_fbo = this;-
1084-
1085 if (d->format.samples() == 0) {
d->format.samples() == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1086 // Create new textures to replace the ones stolen via takeTexture().-
1087 for (int i = 0; i < d->colorAttachments.count(); ++i) {
i < d->colorAt...hments.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1088 if (!d->colorAttachments.at(i).guard)
!d->colorAttac...ts.at(i).guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
1089 d->initTexture(i);
never executed: d->initTexture(i);
0
1090 }
never executed: end of block
0
1091 }
never executed: end of block
0
1092-
1093 return d->valid;
never executed: return d->valid;
0
1094}-
1095-
1096/*!-
1097 \fn bool QOpenGLFramebufferObject::release()-
1098-
1099 Switches rendering back to the default, windowing system provided-
1100 framebuffer.-
1101 Returns \c true upon success, false otherwise.-
1102-
1103 \sa bind()-
1104*/-
1105bool QOpenGLFramebufferObject::release()-
1106{-
1107 if (!isValid())
!isValid()Description
TRUEnever evaluated
FALSEnever evaluated
0
1108 return false;
never executed: return false;
0
1109-
1110 QOpenGLContext *current = QOpenGLContext::currentContext();-
1111 if (!current)
!currentDescription
TRUEnever evaluated
FALSEnever evaluated
0
1112 return false;
never executed: return false;
0
1113-
1114 Q_D(QOpenGLFramebufferObject);-
1115#ifdef QT_DEBUG-
1116 if (current->shareGroup() != d->fbo_guard->group())
current->share...guard->group()Description
TRUEnever evaluated
FALSEnever evaluated
0
1117 qWarning("QOpenGLFramebufferObject::release() called from incompatible context");
never executed: QMessageLogger(__FILE__, 1117, __PRETTY_FUNCTION__).warning("QOpenGLFramebufferObject::release() called from incompatible context");
0
1118#endif-
1119-
1120 if (current) {
currentDescription
TRUEnever evaluated
FALSEnever evaluated
0
1121 d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->defaultFramebufferObject());-
1122-
1123 QOpenGLContextPrivate *contextPrv = QOpenGLContextPrivate::get(current);-
1124 contextPrv->qgl_current_fbo_invalid = true;-
1125 contextPrv->qgl_current_fbo = Q_NULLPTR;-
1126 }
never executed: end of block
0
1127-
1128 return true;
never executed: return true;
0
1129}-
1130-
1131/*!-
1132 \fn GLuint QOpenGLFramebufferObject::texture() const-
1133-
1134 Returns the texture id for the texture attached as the default-
1135 rendering target in this framebuffer object. This texture id can-
1136 be bound as a normal texture in your own OpenGL code.-
1137-
1138 If a multisample framebuffer object is used then the value returned-
1139 from this function will be invalid.-
1140-
1141 When multiple textures are attached, the return value is the ID of-
1142 the first one.-
1143-
1144 \sa takeTexture(), textures()-
1145*/-
1146GLuint QOpenGLFramebufferObject::texture() const-
1147{-
1148 Q_D(const QOpenGLFramebufferObject);-
1149 return d->colorAttachments[0].guard ? d->colorAttachments[0].guard->id() : 0;
never executed: return d->colorAttachments[0].guard ? d->colorAttachments[0].guard->id() : 0;
0
1150}-
1151-
1152/*!-
1153 Returns the texture id for all attached textures.-
1154-
1155 If a multisample framebuffer object is used, then an empty vector is returned.-
1156-
1157 \since 5.6-
1158-
1159 \sa takeTexture(), texture()-
1160*/-
1161QVector<GLuint> QOpenGLFramebufferObject::textures() const-
1162{-
1163 Q_D(const QOpenGLFramebufferObject);-
1164 QVector<GLuint> ids;-
1165 if (d->format.samples() != 0)
d->format.samples() != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1166 return ids;
never executed: return ids;
0
1167 ids.reserve(d->colorAttachments.count());-
1168 for (const auto &color : d->colorAttachments)-
1169 ids.append(color.guard ? color.guard->id() : 0);
never executed: ids.append(color.guard ? color.guard->id() : 0);
0
1170 return ids;
never executed: return ids;
0
1171}-
1172-
1173/*!-
1174 \fn GLuint QOpenGLFramebufferObject::takeTexture()-
1175-
1176 Returns the texture id for the texture attached to this framebuffer-
1177 object. The ownership of the texture is transferred to the caller.-
1178-
1179 If the framebuffer object is currently bound, an implicit release()-
1180 will be done. During the next call to bind() a new texture will be-
1181 created.-
1182-
1183 If a multisample framebuffer object is used, then there is no-
1184 texture and the return value from this function will be invalid.-
1185 Similarly, incomplete framebuffer objects will also return 0.-
1186-
1187 \since 5.3-
1188-
1189 \sa texture(), bind(), release()-
1190 */-
1191GLuint QOpenGLFramebufferObject::takeTexture()-
1192{-
1193 return takeTexture(0);
never executed: return takeTexture(0);
0
1194}-
1195-
1196/*! \overload-
1197-
1198 Returns the texture id for the texture attached to the color attachment of-
1199 index \a colorAttachmentIndex of this framebuffer object. The ownership of-
1200 the texture is transferred to the caller.-
1201-
1202 When \a colorAttachmentIndex is \c 0, the behavior is identical to the-
1203 parameter-less variant of this function.-
1204-
1205 If the framebuffer object is currently bound, an implicit release()-
1206 will be done. During the next call to bind() a new texture will be-
1207 created.-
1208-
1209 If a multisample framebuffer object is used, then there is no-
1210 texture and the return value from this function will be invalid.-
1211 Similarly, incomplete framebuffer objects will also return 0.-
1212-
1213 \since 5.6-
1214 */-
1215GLuint QOpenGLFramebufferObject::takeTexture(int colorAttachmentIndex)-
1216{-
1217 Q_D(QOpenGLFramebufferObject);-
1218 GLuint id = 0;-
1219 if (isValid() && d->format.samples() == 0 && d->colorAttachments.count() > colorAttachmentIndex) {
isValid()Description
TRUEnever evaluated
FALSEnever evaluated
d->format.samples() == 0Description
TRUEnever evaluated
FALSEnever evaluated
d->colorAttach...ttachmentIndexDescription
TRUEnever evaluated
FALSEnever evaluated
0
1220 QOpenGLContext *current = QOpenGLContext::currentContext();-
1221 if (current && current->shareGroup() == d->fbo_guard->group() && isBound())
currentDescription
TRUEnever evaluated
FALSEnever evaluated
current->share...guard->group()Description
TRUEnever evaluated
FALSEnever evaluated
isBound()Description
TRUEnever evaluated
FALSEnever evaluated
0
1222 release();
never executed: release();
0
1223 auto &guard = d->colorAttachments[colorAttachmentIndex].guard;-
1224 id = guard ? guard->id() : 0;
guardDescription
TRUEnever evaluated
FALSEnever evaluated
0
1225 // Do not call free() on texture_guard, just null it out.-
1226 // This way the texture will not be deleted when the guard is destroyed.-
1227 guard = 0;-
1228 }
never executed: end of block
0
1229 return id;
never executed: return id;
0
1230}-
1231-
1232/*!-
1233 \return the size of the color and depth/stencil attachments attached to-
1234 this framebuffer object.-
1235*/-
1236QSize QOpenGLFramebufferObject::size() const-
1237{-
1238 Q_D(const QOpenGLFramebufferObject);-
1239 return d->dsSize;
never executed: return d->dsSize;
0
1240}-
1241-
1242/*!-
1243 \return the sizes of all color attachments attached to this framebuffer-
1244 object.-
1245-
1246 \since 5.6-
1247*/-
1248QVector<QSize> QOpenGLFramebufferObject::sizes() const-
1249{-
1250 Q_D(const QOpenGLFramebufferObject);-
1251 QVector<QSize> sz;-
1252 sz.reserve(d->colorAttachments.size());-
1253 for (const auto &color : d->colorAttachments)-
1254 sz.append(color.size);
never executed: sz.append(color.size);
0
1255 return sz;
never executed: return sz;
0
1256}-
1257-
1258/*!-
1259 \fn int QOpenGLFramebufferObject::width() const-
1260-
1261 Returns the width of the framebuffer object attachments.-
1262*/-
1263-
1264/*!-
1265 \fn int QOpenGLFramebufferObject::height() const-
1266-
1267 Returns the height of the framebuffer object attachments.-
1268*/-
1269-
1270/*!-
1271 Returns the format of this framebuffer object.-
1272*/-
1273QOpenGLFramebufferObjectFormat QOpenGLFramebufferObject::format() const-
1274{-
1275 Q_D(const QOpenGLFramebufferObject);-
1276 return d->format;
never executed: return d->format;
0
1277}-
1278-
1279static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool include_alpha, QOpenGLContext *context)-
1280{-
1281 QOpenGLFunctions *funcs = context->functions();-
1282 const int w = size.width();-
1283 const int h = size.height();-
1284 bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
!context->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
context->forma...Version() >= 2Description
TRUEnever evaluated
FALSEnever evaluated
context->forma...Version() >= 2Description
TRUEnever evaluated
FALSEnever evaluated
0
1285 if (isOpenGL12orBetter) {
isOpenGL12orBetterDescription
TRUEnever evaluated
FALSEnever evaluated
0
1286 QImage img(size, include_alpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);-
1287 funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, img.bits());-
1288 return img;
never executed: return img;
0
1289 }-
1290-
1291#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN-
1292 // Without GL_UNSIGNED_INT_8_8_8_8_REV, GL_BGRA only makes sense on little endian.-
1293 const bool has_bgra_ext = context->isOpenGLES()
context->isOpenGLES()Description
TRUEnever evaluated
FALSEnever evaluated
0
1294 ? context->hasExtension(QByteArrayLiteral("GL_EXT_read_format_bgra"))
never executed: return ba;
0
1295 : context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"));
never executed: return ba;
0
1296-
1297#ifndef Q_OS_IOS-
1298 const char *renderer = reinterpret_cast<const char *>(funcs->glGetString(GL_RENDERER));-
1299 const char *ver = reinterpret_cast<const char *>(funcs->glGetString(GL_VERSION));-
1300-
1301 // Blacklist GPU chipsets that have problems with their BGRA support.-
1302 const bool blackListed = (qstrcmp(renderer, "PowerVR Rogue G6200") == 0
qstrcmp(render...e G6200") == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1303 && ::strstr(ver, "1.3") != 0) ||
::strstr(ver, "1.3") != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1304 (qstrcmp(renderer, "Mali-T760") == 0
qstrcmp(render...li-T760") == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1305 && ::strstr(ver, "3.1") != 0) ||
::strstr(ver, "3.1") != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1306 (qstrcmp(renderer, "Mali-T720") == 0
qstrcmp(render...li-T720") == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1307 && ::strstr(ver, "3.1") != 0) ||
::strstr(ver, "3.1") != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1308 qstrcmp(renderer, "PowerVR SGX 554") == 0;
qstrcmp(render...SGX 554") == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1309#else-
1310 const bool blackListed = true;-
1311#endif-
1312 const bool supports_bgra = has_bgra_ext && !blackListed;
has_bgra_extDescription
TRUEnever evaluated
FALSEnever evaluated
!blackListedDescription
TRUEnever evaluated
FALSEnever evaluated
0
1313-
1314 if (supports_bgra) {
supports_bgraDescription
TRUEnever evaluated
FALSEnever evaluated
0
1315 QImage img(size, include_alpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32);-
1316 funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_BYTE, img.bits());-
1317 return img;
never executed: return img;
0
1318 }-
1319#endif-
1320 QImage rgbaImage(size, include_alpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGBX8888);-
1321 funcs->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits());-
1322 return rgbaImage;
never executed: return rgbaImage;
0
1323}-
1324-
1325static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool include_alpha, QOpenGLContext *context)-
1326{-
1327 // We assume OpenGL 1.2+ or ES 3.0+ here.-
1328 QImage img(size, include_alpha ? QImage::Format_A2BGR30_Premultiplied : QImage::Format_BGR30);-
1329 context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, img.bits());-
1330 return img;
never executed: return img;
0
1331}-
1332-
1333static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip)-
1334{-
1335 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
1336 QOpenGLFunctions *funcs = ctx->functions();-
1337 while (funcs->glGetError());
never executed: ;
funcs->glGetError()Description
TRUEnever evaluated
FALSEnever evaluated
0
1338-
1339 switch (internal_format) {-
1340 case GL_RGB:
never executed: case 0x1907:
0
1341 case GL_RGB8:
never executed: case 0x8051:
0
1342 return qt_gl_read_framebuffer_rgba8(size, false, ctx).mirrored(false, flip);
never executed: return qt_gl_read_framebuffer_rgba8(size, false, ctx).mirrored(false, flip);
0
1343 case GL_RGB10:
never executed: case 0x8052:
0
1344 return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);
never executed: return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);
0
1345 case GL_RGB10_A2:
never executed: case 0x8059:
0
1346 return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);
never executed: return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);
0
1347 case GL_RGBA:
never executed: case 0x1908:
0
1348 case GL_RGBA8:
never executed: case 0x8058:
0
1349 default:
never executed: default:
0
1350 return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).mirrored(false, flip);
never executed: return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).mirrored(false, flip);
0
1351 }-
1352-
1353 Q_UNREACHABLE();
dead code: do { ((!(false)) ? qt_assert_x("Q_UNREACHABLE()", "Q_UNREACHABLE was reached",__FILE__,1353) : qt_noop()); __builtin_unreachable(); } while (0);
-
1354 return QImage();
dead code: return QImage();
-
1355}-
1356-
1357Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)-
1358{-
1359 return qt_gl_read_framebuffer(size, alpha_format ? GL_RGBA : GL_RGB, include_alpha, true);
never executed: return qt_gl_read_framebuffer(size, alpha_format ? 0x1908 : 0x1907, include_alpha, true);
0
1360}-
1361-
1362/*!-
1363 \fn QImage QOpenGLFramebufferObject::toImage(bool flipped) const-
1364-
1365 Returns the contents of this framebuffer object as a QImage.-
1366-
1367 If \a flipped is true the image is flipped from OpenGL coordinates to raster coordinates.-
1368 If used together with QOpenGLPaintDevice, \a flipped should be the opposite of the value-
1369 of QOpenGLPaintDevice::paintFlipped().-
1370-
1371 The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used-
1372 only when internalTextureFormat() is set to \c GL_RGB.-
1373-
1374 If the rendering in the framebuffer was not done with premultiplied alpha in mind,-
1375 create a wrapper QImage with a non-premultiplied format. This is necessary before-
1376 performing operations like QImage::save() because otherwise the image data would get-
1377 unpremultiplied, even though it was not premultiplied in the first place. To create-
1378 such a wrapper without performing a copy of the pixel data, do the following:-
1379-
1380 \code-
1381 QImage fboImage(fbo.toImage());-
1382 QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32);-
1383 \endcode-
1384-
1385 Since Qt 5.2 the function will fall back to premultiplied RGBA8888 or RGBx8888 when-
1386 reading to (A)RGB32 is not supported. Since 5.4 an A2BGR30 image is returned if the-
1387 internal format is RGB10_A2.-
1388-
1389 For multisampled framebuffer objects the samples are resolved using the-
1390 \c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents-
1391 of the returned image is undefined.-
1392-
1393 For singlesampled framebuffers the contents is retrieved via \c glReadPixels. This is-
1394 a potentially expensive and inefficient operation. Therefore it is recommended that-
1395 this function is used as seldom as possible.-
1396-
1397 \sa QOpenGLPaintDevice::paintFlipped()-
1398*/-
1399-
1400QImage QOpenGLFramebufferObject::toImage(bool flipped) const-
1401{-
1402 return toImage(flipped, 0);
never executed: return toImage(flipped, 0);
0
1403}-
1404-
1405/*!-
1406 \fn QImage QOpenGLFramebufferObject::toImage() const-
1407 \overload-
1408-
1409 Returns the contents of this framebuffer object as a QImage. This method flips-
1410 the image from OpenGL coordinates to raster coordinates.-
1411*/-
1412// ### Qt 6: Remove this method and make it a default argument instead.-
1413QImage QOpenGLFramebufferObject::toImage() const-
1414{-
1415 return toImage(true, 0);
never executed: return toImage(true, 0);
0
1416}-
1417-
1418/*! \overload-
1419-
1420 Returns the contents of the color attachment of index \a-
1421 colorAttachmentIndex of this framebuffer object as a QImage. This method-
1422 flips the image from OpenGL coordinates to raster coordinates when \a-
1423 flipped is set to \c true.-
1424-
1425 \note This overload is only fully functional when multiple render targets are-
1426 supported by the OpenGL implementation. When that is not the case, only one-
1427 color attachment will be set up.-
1428-
1429 \since 5.6-
1430*/-
1431QImage QOpenGLFramebufferObject::toImage(bool flipped, int colorAttachmentIndex) const-
1432{-
1433 Q_D(const QOpenGLFramebufferObject);-
1434 if (!d->valid)
!d->validDescription
TRUEnever evaluated
FALSEnever evaluated
0
1435 return QImage();
never executed: return QImage();
0
1436-
1437 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
1438 if (!ctx) {
!ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
1439 qWarning("QOpenGLFramebufferObject::toImage() called without a current context");-
1440 return QImage();
never executed: return QImage();
0
1441 }-
1442-
1443 if (d->colorAttachments.count() <= colorAttachmentIndex) {
d->colorAttach...ttachmentIndexDescription
TRUEnever evaluated
FALSEnever evaluated
0
1444 qWarning("QOpenGLFramebufferObject::toImage() called for missing color attachment");-
1445 return QImage();
never executed: return QImage();
0
1446 }-
1447-
1448 GLuint prevFbo = 0;-
1449 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);-
1450-
1451 if (prevFbo != d->fbo())
prevFbo != d->fbo()Description
TRUEnever evaluated
FALSEnever evaluated
0
1452 const_cast<QOpenGLFramebufferObject *>(this)->bind();
never executed: const_cast<QOpenGLFramebufferObject *>(this)->bind();
0
1453-
1454 QImage image;-
1455 QOpenGLExtraFunctions *extraFuncs = ctx->extraFunctions();-
1456 // qt_gl_read_framebuffer doesn't work on a multisample FBO-
1457 if (format().samples() != 0) {
format().samples() != 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1458 QRect rect(QPoint(0, 0), size());-
1459 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
extraFuncs->ha...RenderTargets)Description
TRUEnever evaluated
FALSEnever evaluated
0
1460 QOpenGLFramebufferObject temp(d->colorAttachments[colorAttachmentIndex].size, QOpenGLFramebufferObjectFormat());-
1461 blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect,-
1462 GL_COLOR_BUFFER_BIT, GL_NEAREST,-
1463 colorAttachmentIndex, 0);-
1464 image = temp.toImage(flipped);-
1465 } else {
never executed: end of block
0
1466 QOpenGLFramebufferObject temp(size(), QOpenGLFramebufferObjectFormat());-
1467 blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect);-
1468 image = temp.toImage(flipped);-
1469 }
never executed: end of block
0
1470 } else {-
1471 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
extraFuncs->ha...RenderTargets)Description
TRUEnever evaluated
FALSEnever evaluated
0
1472 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachmentIndex);-
1473 image = qt_gl_read_framebuffer(d->colorAttachments[colorAttachmentIndex].size,-
1474 d->colorAttachments[colorAttachmentIndex].internalFormat,-
1475 true, flipped);-
1476 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0);-
1477 } else {
never executed: end of block
0
1478 image = qt_gl_read_framebuffer(d->colorAttachments[0].size,-
1479 d->colorAttachments[0].internalFormat,-
1480 true, flipped);-
1481 }
never executed: end of block
0
1482 }-
1483-
1484 if (prevFbo != d->fbo())
prevFbo != d->fbo()Description
TRUEnever evaluated
FALSEnever evaluated
0
1485 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
never executed: ctx->functions()->glBindFramebuffer(0x8D40, prevFbo);
0
1486-
1487 return image;
never executed: return image;
0
1488}-
1489-
1490/*!-
1491 \fn bool QOpenGLFramebufferObject::bindDefault()-
1492-
1493 Switches rendering back to the default, windowing system provided-
1494 framebuffer.-
1495 Returns \c true upon success, false otherwise.-
1496-
1497 \sa bind(), release()-
1498*/-
1499bool QOpenGLFramebufferObject::bindDefault()-
1500{-
1501 QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());-
1502-
1503 if (ctx) {
ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
1504 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());-
1505 QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true;-
1506 QOpenGLContextPrivate::get(ctx)->qgl_current_fbo = Q_NULLPTR;-
1507 }
never executed: end of block
0
1508#ifdef QT_DEBUG-
1509 else-
1510 qWarning("QOpenGLFramebufferObject::bindDefault() called without current context.");
never executed: QMessageLogger(__FILE__, 1510, __PRETTY_FUNCTION__).warning("QOpenGLFramebufferObject::bindDefault() called without current context.");
0
1511#endif-
1512-
1513 return ctx != 0;
never executed: return ctx != 0;
0
1514}-
1515-
1516/*!-
1517 \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()-
1518-
1519 Returns \c true if the OpenGL \c{GL_EXT_framebuffer_object} extension-
1520 is present on this system; otherwise returns \c false.-
1521*/-
1522bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()-
1523{-
1524 return QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::Framebuffers);
never executed: return QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::Framebuffers);
0
1525}-
1526-
1527/*!-
1528 \fn GLuint QOpenGLFramebufferObject::handle() const-
1529-
1530 Returns the OpenGL framebuffer object handle for this framebuffer-
1531 object (returned by the \c{glGenFrameBuffersEXT()} function). This-
1532 handle can be used to attach new images or buffers to the-
1533 framebuffer. The user is responsible for cleaning up and-
1534 destroying these objects.-
1535*/-
1536GLuint QOpenGLFramebufferObject::handle() const-
1537{-
1538 Q_D(const QOpenGLFramebufferObject);-
1539 return d->fbo();
never executed: return d->fbo();
0
1540}-
1541-
1542/*!-
1543 Returns the status of the depth and stencil buffers attached to-
1544 this framebuffer object.-
1545*/-
1546-
1547QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() const-
1548{-
1549 Q_D(const QOpenGLFramebufferObject);-
1550 if (d->valid)
d->validDescription
TRUEnever evaluated
FALSEnever evaluated
0
1551 return d->fbo_attachment;
never executed: return d->fbo_attachment;
0
1552 return NoAttachment;
never executed: return NoAttachment;
0
1553}-
1554-
1555/*!-
1556 Sets the attachments of the framebuffer object to \a attachment.-
1557-
1558 This can be used to free or reattach the depth and stencil buffer-
1559 attachments as needed.-
1560-
1561 \note This function alters the current framebuffer binding.-
1562 */-
1563void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment)-
1564{-
1565 Q_D(QOpenGLFramebufferObject);-
1566 if (attachment == d->fbo_attachment || !isValid())
attachment == ...fbo_attachmentDescription
TRUEnever evaluated
FALSEnever evaluated
!isValid()Description
TRUEnever evaluated
FALSEnever evaluated
0
1567 return;
never executed: return;
0
1568 QOpenGLContext *current = QOpenGLContext::currentContext();-
1569 if (!current)
!currentDescription
TRUEnever evaluated
FALSEnever evaluated
0
1570 return;
never executed: return;
0
1571#ifdef QT_DEBUG-
1572 if (current->shareGroup() != d->fbo_guard->group())
current->share...guard->group()Description
TRUEnever evaluated
FALSEnever evaluated
0
1573 qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");
never executed: QMessageLogger(__FILE__, 1573, __PRETTY_FUNCTION__).warning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");
0
1574#endif-
1575 d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());-
1576 QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true;-
1577 d->initDepthStencilAttachments(current, attachment);-
1578}
never executed: end of block
0
1579-
1580/*!-
1581 Returns \c true if the framebuffer object is currently bound to the current context,-
1582 otherwise false is returned.-
1583*/-
1584bool QOpenGLFramebufferObject::isBound() const-
1585{-
1586 Q_D(const QOpenGLFramebufferObject);-
1587 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
1588 if (!ctx)
!ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
1589 return false;
never executed: return false;
0
1590 GLint fbo = 0;-
1591 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);-
1592 return GLuint(fbo) == d->fbo();
never executed: return GLuint(fbo) == d->fbo();
0
1593}-
1594-
1595/*!-
1596 \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()-
1597-
1598 Returns \c true if the OpenGL \c{GL_EXT_framebuffer_blit} extension-
1599 is present on this system; otherwise returns \c false.-
1600-
1601 \sa blitFramebuffer()-
1602*/-
1603bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()-
1604{-
1605 return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
never executed: return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
0
1606}-
1607-
1608-
1609/*!-
1610 \overload-
1611-
1612 Convenience overload to blit between two framebuffer objects.-
1613*/-
1614void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,-
1615 QOpenGLFramebufferObject *source,-
1616 GLbitfield buffers, GLenum filter)-
1617{-
1618 if (!target && !source)
!targetDescription
TRUEnever evaluated
FALSEnever evaluated
!sourceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1619 return;
never executed: return;
0
1620-
1621 QSize targetSize;-
1622 QSize sourceSize;-
1623-
1624 if (target)
targetDescription
TRUEnever evaluated
FALSEnever evaluated
0
1625 targetSize = target->size();
never executed: targetSize = target->size();
0
1626 if (source)
sourceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1627 sourceSize = source->size();
never executed: sourceSize = source->size();
0
1628-
1629 if (targetSize.isEmpty())
targetSize.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1630 targetSize = sourceSize;
never executed: targetSize = sourceSize;
0
1631 else if (sourceSize.isEmpty())
sourceSize.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1632 sourceSize = targetSize;
never executed: sourceSize = targetSize;
0
1633-
1634 blitFramebuffer(target, QRect(QPoint(0, 0), targetSize),-
1635 source, QRect(QPoint(0, 0), sourceSize),-
1636 buffers, filter);-
1637}
never executed: end of block
0
1638-
1639/*! \overload-
1640 *-
1641 Convenience overload to blit between two framebuffer objects.-
1642*/-
1643void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,-
1644 QOpenGLFramebufferObject *source, const QRect &sourceRect,-
1645 GLbitfield buffers,-
1646 GLenum filter)-
1647{-
1648 blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter, 0, 0);-
1649}
never executed: end of block
0
1650-
1651/*!-
1652 \enum QOpenGLFramebufferObject::FramebufferRestorePolicy-
1653 \since 5.7-
1654-
1655 This enum type is used to configure the behavior related to restoring-
1656 framebuffer bindings when calling blitFramebuffer().-
1657-
1658 \value DontRestoreFramebufferBinding Do not restore the previous framebuffer binding.-
1659 The caller is responsible for tracking and setting-
1660 the framebuffer binding as needed.-
1661-
1662 \value RestoreFramebufferBindingToDefault After the blit operation, bind the default-
1663 framebuffer.-
1664-
1665 \value RestoreFrameBufferBinding Restore the previously bound framebuffer. This is-
1666 potentially expensive because of the need to-
1667 query the currently bound framebuffer.-
1668-
1669 \sa blitFramebuffer()-
1670*/-
1671-
1672/*!-
1673 \since 5.7-
1674-
1675 Blits from the \a sourceRect rectangle in the \a source framebuffer-
1676 object to the \a targetRect rectangle in the \a target framebuffer object.-
1677-
1678 If \a source or \a target is 0, the default framebuffer will be used-
1679 instead of a framebuffer object as source or target respectively.-
1680-
1681 This function will have no effect unless hasOpenGLFramebufferBlit() returns-
1682 true.-
1683-
1684 The \a buffers parameter should be a mask consisting of any combination of-
1685 \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and-
1686 \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both-
1687 in the source and target buffers is ignored.-
1688-
1689 The \a sourceRect and \a targetRect rectangles may have different sizes;-
1690 in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or-
1691 \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to-
1692 \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest-
1693 interpolation should be used when scaling is performed.-
1694-
1695 If \a source equals \a target a copy is performed within the same buffer.-
1696 Results are undefined if the source and target rectangles overlap and-
1697 have different sizes. The sizes must also be the same if any of the-
1698 framebuffer objects are multisample framebuffers.-
1699-
1700 \note The scissor test will restrict the blit area if enabled.-
1701-
1702 When multiple render targets are in use, \a readColorAttachmentIndex and \a-
1703 drawColorAttachmentIndex specify the index of the color attachments in the-
1704 source and destination framebuffers.-
1705-
1706 The \a restorePolicy determines if the framebuffer that was bound prior to-
1707 calling this function should be restored, or if the default framebuffer-
1708 should be bound before returning, of if the caller is responsible for-
1709 tracking and setting the bound framebuffer. Restoring the previous-
1710 framebuffer can be relatively expensive due to the call to \c{glGetIntegerv}-
1711 which on some OpenGL drivers may imply a pipeline stall.-
1712-
1713 \sa hasOpenGLFramebufferBlit()-
1714*/-
1715void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,-
1716 QOpenGLFramebufferObject *source, const QRect &sourceRect,-
1717 GLbitfield buffers,-
1718 GLenum filter,-
1719 int readColorAttachmentIndex,-
1720 int drawColorAttachmentIndex,-
1721 QOpenGLFramebufferObject::FramebufferRestorePolicy restorePolicy)-
1722{-
1723 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
1724 if (!ctx)
!ctxDescription
TRUEnever evaluated
FALSEnever evaluated
0
1725 return;
never executed: return;
0
1726-
1727 QOpenGLExtensions extensions(ctx);-
1728 if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
!extensions.ha...amebufferBlit)Description
TRUEnever evaluated
FALSEnever evaluated
0
1729 return;
never executed: return;
0
1730-
1731 GLuint prevFbo = 0;-
1732 if (restorePolicy == RestoreFrameBufferBinding)
restorePolicy ...eBufferBindingDescription
TRUEnever evaluated
FALSEnever evaluated
0
1733 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
never executed: ctx->functions()->glGetIntegerv(0x8CA6, (GLint *) &prevFbo);
0
1734-
1735 const int sx0 = sourceRect.left();-
1736 const int sx1 = sourceRect.left() + sourceRect.width();-
1737 const int sy0 = sourceRect.top();-
1738 const int sy1 = sourceRect.top() + sourceRect.height();-
1739-
1740 const int tx0 = targetRect.left();-
1741 const int tx1 = targetRect.left() + targetRect.width();-
1742 const int ty0 = targetRect.top();-
1743 const int ty1 = targetRect.top() + targetRect.height();-
1744-
1745 const GLuint defaultFboId = ctx->defaultFramebufferObject();-
1746-
1747 extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);-
1748 extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);-
1749-
1750 const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets);-
1751 if (supportsMRT) {
supportsMRTDescription
TRUEnever evaluated
FALSEnever evaluated
0
1752 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0 + readColorAttachmentIndex);-
1753 if (target) {
targetDescription
TRUEnever evaluated
FALSEnever evaluated
0
1754 GLenum drawBuf = GL_COLOR_ATTACHMENT0 + drawColorAttachmentIndex;-
1755 extensions.glDrawBuffers(1, &drawBuf);-
1756 }
never executed: end of block
0
1757 }
never executed: end of block
0
1758-
1759 extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,-
1760 tx0, ty0, tx1, ty1,-
1761 buffers, filter);-
1762-
1763 if (supportsMRT)
supportsMRTDescription
TRUEnever evaluated
FALSEnever evaluated
0
1764 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0);
never executed: extensions.glReadBuffer(0x8CE0);
0
1765-
1766 switch (restorePolicy) {-
1767 case RestoreFrameBufferBinding:
never executed: case RestoreFrameBufferBinding:
0
1768 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW-
1769 break;
never executed: break;
0
1770-
1771 case RestoreFramebufferBindingToDefault:
never executed: case RestoreFramebufferBindingToDefault:
0
1772 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); // sets both READ and DRAW-
1773 break;
never executed: break;
0
1774-
1775 case DontRestoreFramebufferBinding:
never executed: case DontRestoreFramebufferBinding:
0
1776 break;
never executed: break;
0
1777 }-
1778}
never executed: end of block
0
1779-
1780/*!-
1781 \overload-
1782-
1783 Convenience overload to blit between two framebuffer objects and-
1784 to restore the previous framebuffer binding. Equivalent to calling-
1785 blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter,-
1786 readColorAttachmentIndex, drawColorAttachmentIndex,-
1787 RestoreFrameBufferBinding).-
1788*/-
1789void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,-
1790 QOpenGLFramebufferObject *source, const QRect &sourceRect,-
1791 GLbitfield buffers,-
1792 GLenum filter,-
1793 int readColorAttachmentIndex,-
1794 int drawColorAttachmentIndex)-
1795{-
1796 blitFramebuffer(target, targetRect, source, sourceRect,-
1797 buffers, filter,-
1798 readColorAttachmentIndex,-
1799 drawColorAttachmentIndex,-
1800 RestoreFrameBufferBinding);-
1801}
never executed: end of block
0
1802-
1803QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9