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) {-
163 QOpenGLFramebufferObjectFormatPrivate *newd-
164 = new QOpenGLFramebufferObjectFormatPrivate(d);-
165 if (!d->ref.deref())-
166 delete d;-
167 d = newd;-
168 }-
169}-
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}-
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}-
196-
197/*!-
198 Assigns \a other to this object.-
199*/-
200-
201QOpenGLFramebufferObjectFormat &QOpenGLFramebufferObjectFormat::operator=(const QOpenGLFramebufferObjectFormat &other)-
202{-
203 if (d != other.d) {-
204 other.d->ref.ref();-
205 if (!d->ref.deref())-
206 delete d;-
207 d = other.d;-
208 }-
209 return *this;-
210}-
211-
212/*!-
213 Destroys the QOpenGLFramebufferObjectFormat.-
214*/-
215QOpenGLFramebufferObjectFormat::~QOpenGLFramebufferObjectFormat()-
216{-
217 if (!d->ref.deref())-
218 delete d;-
219}-
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}-
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;-
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}-
269-
270/*!-
271 Returns \c true if mipmapping is enabled.-
272-
273 \sa setMipmap()-
274*/-
275bool QOpenGLFramebufferObjectFormat::mipmap() const-
276{-
277 return d->mipmap;-
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}-
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;-
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}-
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;-
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}-
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;-
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)-
359 return true;-
360 else-
361 return d->equals(other.d);-
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);-
371}-
372-
373bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus(QOpenGLContext *ctx) const-
374{-
375 if (!ctx)-
376 return false; // Context no longer exists.-
377 GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);-
378 switch(status) {-
379 case GL_NO_ERROR:-
380 case GL_FRAMEBUFFER_COMPLETE:-
381 return true;-
382 case GL_FRAMEBUFFER_UNSUPPORTED:-
383 qDebug("QOpenGLFramebufferObject: Unsupported framebuffer format.");-
384 break;-
385 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:-
386 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete attachment.");-
387 break;-
388 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:-
389 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment.");-
390 break;-
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:-
408 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");-
409 break;-
410#endif-
411#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER-
412 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:-
413 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing read buffer.");-
414 break;-
415#endif-
416#ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE-
417 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:-
418 qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");-
419 break;-
420#endif-
421 default:-
422 qDebug() <<"QOpenGLFramebufferObject: An undefined error has occurred: "<< status;-
423 break;-
424 }-
425 return false;-
426}-
427-
428namespace-
429{-
430 void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)-
431 {-
432 funcs->glDeleteFramebuffers(1, &id);-
433 }-
434-
435 void freeRenderbufferFunc(QOpenGLFunctions *funcs, GLuint id)-
436 {-
437 funcs->glDeleteRenderbuffers(1, &id);-
438 }-
439-
440 void freeTextureFunc(QOpenGLFunctions *funcs, GLuint id)-
441 {-
442 funcs->glDeleteTextures(1, &id);-
443 }-
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))-
456 return;-
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)-
460 || !funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) {-
461 samples = 0;-
462 } else if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {-
463 GLint maxSamples;-
464 funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);-
465 samples = qBound(0, int(samples), int(maxSamples));-
466 }-
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-
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();-
486-
487 format.setTextureTarget(target);-
488 format.setInternalTextureFormat(internal_format);-
489 format.setMipmap(mipmap);-
490-
491 if (samples == 0)-
492 initTexture(0);-
493 else-
494 initColorBuffer(0, &samples);-
495-
496 format.setSamples(int(samples));-
497-
498 initDepthStencilAttachments(ctx, attachment);-
499-
500 if (valid)-
501 fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);-
502 else-
503 funcs.glDeleteFramebuffers(1, &fbo);-
504-
505 QT_CHECK_GLERROR();-
506}-
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)-
525 pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;-
526-
527 funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,-
528 GL_RGBA, pixelType, NULL);-
529 if (format.mipmap()) {-
530 int width = color.size.width();-
531 int height = color.size.height();-
532 int level = 0;-
533 while (width > 1 || height > 1) {-
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 }-
540 }-
541 funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx,-
542 target, texture, 0);-
543-
544 QT_CHECK_GLERROR();-
545 funcs.glBindTexture(target, 0);-
546 valid = checkFramebufferStatus(ctx);-
547 if (valid) {-
548 color.guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);-
549 } else {-
550 funcs.glDeleteTextures(1, &texture);-
551 }-
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) {-
564 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Sized8Formats))-
565 storageFormat = GL_RGBA8;-
566 else-
567 storageFormat = GL_RGBA4;-
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();-
577 valid = checkFramebufferStatus(ctx);-
578 if (valid) {-
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 {-
585 funcs.glDeleteRenderbuffers(1, &color_buffer);-
586 }-
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) {-
599 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);-
600 depth_buffer_guard->free();-
601 }-
602 if (stencil_buffer_guard) {-
603 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);-
604 if (stencil_buffer_guard != depth_buffer_guard)-
605 stencil_buffer_guard->free();-
606 }-
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-
619 && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))-
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))-
626 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,-
627 GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height());-
628 else-
629 funcs.glRenderbufferStorage(GL_RENDERBUFFER,-
630 GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height());-
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) {-
640 funcs.glDeleteRenderbuffers(1, &depth_buffer);-
641 stencil_buffer = depth_buffer = 0;-
642 }-
643 }-
644-
645 if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil-
646 || (attachment == QOpenGLFramebufferObject::Depth)))-
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)) {-
652 if (ctx->isOpenGLES()) {-
653 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24))-
654 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,-
655 GL_DEPTH_COMPONENT24, dsSize.width(), dsSize.height());-
656 else-
657 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,-
658 GL_DEPTH_COMPONENT16, dsSize.width(), dsSize.height());-
659 } else {-
660 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,-
661 GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());-
662 }-
663 } else {-
664 if (ctx->isOpenGLES()) {-
665 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {-
666 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24,-
667 dsSize.width(), dsSize.height());-
668 } else {-
669 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,-
670 dsSize.width(), dsSize.height());-
671 }-
672 } else {-
673 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());-
674 }-
675 }-
676 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,-
677 GL_RENDERBUFFER, depth_buffer);-
678 valid = checkFramebufferStatus(ctx);-
679 if (!valid) {-
680 funcs.glDeleteRenderbuffers(1, &depth_buffer);-
681 depth_buffer = 0;-
682 }-
683 }-
684-
685 if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) {-
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;-
694#endif-
695-
696 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))-
697 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, dsSize.width(), dsSize.height());-
698 else-
699 funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, dsSize.width(), dsSize.height());-
700-
701 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,-
702 GL_RENDERBUFFER, stencil_buffer);-
703 valid = checkFramebufferStatus(ctx);-
704 if (!valid) {-
705 funcs.glDeleteRenderbuffers(1, &stencil_buffer);-
706 stencil_buffer = 0;-
707 }-
708 }-
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) {-
714 fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;-
715 } else if (depth_buffer) {-
716 fbo_attachment = QOpenGLFramebufferObject::Depth;-
717 } else {-
718 fbo_attachment = QOpenGLFramebufferObject::NoAttachment;-
719 }-
720-
721 if (valid) {-
722 if (depth_buffer)-
723 depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);-
724 if (stencil_buffer) {-
725 if (stencil_buffer == depth_buffer)-
726 stencil_buffer_guard = depth_buffer_guard;-
727 else-
728 stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);-
729 }-
730 } else {-
731 if (depth_buffer)-
732 funcs.glDeleteRenderbuffers(1, &depth_buffer);-
733 if (stencil_buffer && depth_buffer != stencil_buffer)-
734 funcs.glDeleteRenderbuffers(1, &stencil_buffer);-
735 }-
736 QT_CHECK_GLERROR();-
737-
738 format.setAttachment(fbo_attachment);-
739}-
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)-
812#ifdef QT_OPENGL_ES_2-
813 internalFormat = GL_RGBA;-
814#else-
815 internalFormat = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8;-
816#endif-
817 return internalFormat;-
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}-
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}-
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}-
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}-
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}-
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}-
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 foreachfor (const QOpenGLFramebufferObjectPrivate::ColorAttachmentauto &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)) {-
1000 qWarning("Multiple render targets not supported, ignoring extra color attachment request");-
1001 return;-
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) {-
1009 d->initTexture(idx);-
1010 } else {-
1011 GLint samples = d->requestedSamples;-
1012 d->initColorBuffer(idx, &samples);-
1013 }-
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}-
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();-
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())-
1108 return false;-
1109-
1110 QOpenGLContext *current = QOpenGLContext::currentContext();-
1111 if (!current)-
1112 return false;-
1113-
1114 Q_D(QOpenGLFramebufferObject);-
1115#ifdef QT_DEBUG-
1116 if (current->shareGroup() != d->fbo_guard->group())-
1117 qWarning("QOpenGLFramebufferObject::release() called from incompatible context");-
1118#endif-
1119-
1120 if (current) {-
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 }-
1127-
1128 return true;-
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;-
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 foreachfor (const QOpenGLFramebufferObjectPrivate::ColorAttachmentauto &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);-
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 idauto &guard = d->colorAttachments[colorAttachmentIndex].guard;-
1224 id =
guardDescription
TRUEnever evaluated
FALSEnever evaluated
guard ? d->colorAttachments[colorAttachmentIndex].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 d->colorAttachments[colorAttachmentIndex].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;-
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 foreachfor (const QOpenGLFramebufferObjectPrivate::ColorAttachmentauto &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;-
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);-
1285 if (isOpenGL12orBetter) {-
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;-
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()-
1294 ? context->hasExtension(QByteArrayLiteral("GL_EXT_read_format_bgra"))-
1295 : context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"));-
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-
1303 && ::strstr(ver, "1.3") != 0) ||-
1304 (qstrcmp(renderer, "Mali-T760") == 0-
1305 && ::strstr(ver, "3.1") != 0) ||-
1306 (qstrcmp(renderer, "Mali-T720") == 0-
1307 && ::strstr(ver, "3.1") != 0) ||-
1308 qstrcmp(renderer, "PowerVR SGX 554") == 0;-
1309#else-
1310 const bool blackListed = true;-
1311#endif-
1312 const bool supports_bgra = has_bgra_ext && !blackListed;-
1313-
1314 if (supports_bgra) {-
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;-
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;-
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;-
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());-
1338-
1339 switch (internal_format) {-
1340 case GL_RGB:-
1341 case GL_RGB8:-
1342 return qt_gl_read_framebuffer_rgba8(size, false, ctx).mirrored(false, flip);-
1343 case GL_RGB10:-
1344 return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip);-
1345 case GL_RGB10_A2:-
1346 return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip);-
1347 case GL_RGBA:-
1348 case GL_RGBA8:-
1349 default:-
1350 return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).mirrored(false, flip);-
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);-
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);-
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);-
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)-
1435 return QImage();-
1436-
1437 QOpenGLContext *ctx = QOpenGLContext::currentContext();-
1438 if (!ctx) {-
1439 qWarning("QOpenGLFramebufferObject::toImage() called without a current context");-
1440 return QImage();-
1441 }-
1442-
1443 if (d->colorAttachments.count() <= colorAttachmentIndex) {-
1444 qWarning("QOpenGLFramebufferObject::toImage() called for missing color attachment");-
1445 return QImage();-
1446 }-
1447-
1448 GLuint prevFbo = 0;-
1449 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);-
1450-
1451 if (prevFbo != d->fbo())-
1452 const_cast<QOpenGLFramebufferObject *>(this)->bind();-
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) {-
1458 QRect rect(QPoint(0, 0), size());-
1459 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {-
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 {-
1466 QOpenGLFramebufferObject temp(size(), QOpenGLFramebufferObjectFormat());-
1467 blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect);-
1468 image = temp.toImage(flipped);-
1469 }-
1470 } else {-
1471 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {-
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 {-
1478 image = qt_gl_read_framebuffer(d->colorAttachments[0].size,-
1479 d->colorAttachments[0].internalFormat,-
1480 true, flipped);-
1481 }-
1482 }-
1483-
1484 if (prevFbo != d->fbo())-
1485 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);-
1486-
1487 return image;-
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) {-
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 }-
1508#ifdef QT_DEBUG-
1509 else-
1510 qWarning("QOpenGLFramebufferObject::bindDefault() called without current context.");-
1511#endif-
1512-
1513 return ctx != 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);-
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();-
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)-
1551 return d->fbo_attachment;-
1552 return NoAttachment;-
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())-
1567 return;-
1568 QOpenGLContext *current = QOpenGLContext::currentContext();-
1569 if (!current)-
1570 return;-
1571#ifdef QT_DEBUG-
1572 if (current->shareGroup() != d->fbo_guard->group())-
1573 qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");-
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}-
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)-
1589 return false;-
1590 GLint fbo = 0;-
1591 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);-
1592 return GLuint(fbo) == d->fbo();-
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);-
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)-
1619 return;-
1620-
1621 QSize targetSize;-
1622 QSize sourceSize;-
1623-
1624 if (target)-
1625 targetSize = target->size();-
1626 if (source)-
1627 sourceSize = source->size();-
1628-
1629 if (targetSize.isEmpty())-
1630 targetSize = sourceSize;-
1631 else if (sourceSize.isEmpty())-
1632 sourceSize = targetSize;-
1633-
1634 blitFramebuffer(target, QRect(QPoint(0, 0), targetSize),-
1635 source, QRect(QPoint(0, 0), sourceSize),-
1636 buffers, filter);-
1637}-
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}-
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 if (const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)));-
1751 if (supportsMRT)
supportsMRTDescription
TRUEnever evaluated
FALSEnever evaluated
{
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 (extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets))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
never executed: break;
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