Added support for resetting QOpenGLFramebufferObject attachments.
[profile/ivi/qtbase.git] / src / gui / opengl / qopenglframebufferobject.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qopenglframebufferobject.h"
43 #include "qopenglframebufferobject_p.h"
44
45 #include <qdebug.h>
46 #include <private/qopengl_p.h>
47 #include <private/qopenglcontext_p.h>
48 #include <private/qopenglextensions_p.h>
49 #include <private/qfont_p.h>
50
51 #include <qwindow.h>
52 #include <qlibrary.h>
53 #include <qimage.h>
54
55 QT_BEGIN_NAMESPACE
56
57 #ifndef QT_NO_DEBUG
58 #define QT_RESET_GLERROR()                                \
59 {                                                         \
60     while (glGetError() != GL_NO_ERROR) {}                \
61 }
62 #define QT_CHECK_GLERROR()                                \
63 {                                                         \
64     GLenum err = glGetError();                            \
65     if (err != GL_NO_ERROR) {                             \
66         qDebug("[%s line %d] GL Error: %d",               \
67                __FILE__, __LINE__, (int)err);             \
68     }                                                     \
69 }
70 #else
71 #define QT_RESET_GLERROR() {}
72 #define QT_CHECK_GLERROR() {}
73 #endif
74
75 /*!
76     \class QOpenGLFramebufferObjectFormat
77     \brief The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL
78     framebuffer object.
79
80     \since 5.0
81
82     \ingroup painting-3D
83
84     A framebuffer object has several characteristics:
85     \list
86     \i \link setSamples() Number of samples per pixels.\endlink
87     \i \link setAttachment() Depth and/or stencil attachments.\endlink
88     \i \link setTextureTarget() Texture target.\endlink
89     \i \link setInternalTextureFormat() Internal texture format.\endlink
90     \endlist
91
92     Note that the desired attachments or number of samples per pixels might not
93     be supported by the hardware driver. Call QOpenGLFramebufferObject::format()
94     after creating a QOpenGLFramebufferObject to find the exact format that was
95     used to create the frame buffer object.
96
97     \sa QOpenGLFramebufferObject
98 */
99
100 /*!
101     \internal
102 */
103 void QOpenGLFramebufferObjectFormat::detach()
104 {
105     if (d->ref.load() != 1) {
106         QOpenGLFramebufferObjectFormatPrivate *newd
107             = new QOpenGLFramebufferObjectFormatPrivate(d);
108         if (!d->ref.deref())
109             delete d;
110         d = newd;
111     }
112 }
113
114 /*!
115     Creates a QOpenGLFramebufferObjectFormat object for specifying
116     the format of an OpenGL framebuffer object.
117
118     By default the format specifies a non-multisample framebuffer object with no
119     attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
120     On OpenGL/ES systems, the default internal format is \c GL_RGBA.
121
122     \sa samples(), attachment(), internalTextureFormat()
123 */
124
125 QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat()
126 {
127     d = new QOpenGLFramebufferObjectFormatPrivate;
128 }
129
130 /*!
131     Constructs a copy of \a other.
132 */
133
134 QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other)
135 {
136     d = other.d;
137     d->ref.ref();
138 }
139
140 /*!
141     Assigns \a other to this object.
142 */
143
144 QOpenGLFramebufferObjectFormat &QOpenGLFramebufferObjectFormat::operator=(const QOpenGLFramebufferObjectFormat &other)
145 {
146     if (d != other.d) {
147         other.d->ref.ref();
148         if (!d->ref.deref())
149             delete d;
150         d = other.d;
151     }
152     return *this;
153 }
154
155 /*!
156     Destroys the QOpenGLFramebufferObjectFormat.
157 */
158 QOpenGLFramebufferObjectFormat::~QOpenGLFramebufferObjectFormat()
159 {
160     if (!d->ref.deref())
161         delete d;
162 }
163
164 /*!
165     Sets the number of samples per pixel for a multisample framebuffer object
166     to \a samples.  The default sample count of 0 represents a regular
167     non-multisample framebuffer object.
168
169     If the desired amount of samples per pixel is not supported by the hardware
170     then the maximum number of samples per pixel will be used. Note that
171     multisample framebuffer objects can not be bound as textures. Also, the
172     \c{GL_EXT_framebuffer_multisample} extension is required to create a
173     framebuffer with more than one sample per pixel.
174
175     \sa samples()
176 */
177 void QOpenGLFramebufferObjectFormat::setSamples(int samples)
178 {
179     detach();
180     d->samples = samples;
181 }
182
183 /*!
184     Returns the number of samples per pixel if a framebuffer object
185     is a multisample framebuffer object. Otherwise, returns 0.
186     The default value is 0.
187
188     \sa setSamples()
189 */
190 int QOpenGLFramebufferObjectFormat::samples() const
191 {
192     return d->samples;
193 }
194
195 /*!
196     Enables mipmapping if \a enabled is true; otherwise disables it.
197
198     Mipmapping is disabled by default.
199
200     If mipmapping is enabled, additional memory will be allocated for
201     the mipmap levels. The mipmap levels can be updated by binding the
202     texture and calling glGenerateMipmap(). Mipmapping cannot be enabled
203     for multisampled framebuffer objects.
204
205     \sa mipmap(), QOpenGLFramebufferObject::texture()
206 */
207 void QOpenGLFramebufferObjectFormat::setMipmap(bool enabled)
208 {
209     detach();
210     d->mipmap = enabled;
211 }
212
213 /*!
214     Returns true if mipmapping is enabled.
215
216     \sa setMipmap()
217 */
218 bool QOpenGLFramebufferObjectFormat::mipmap() const
219 {
220     return d->mipmap;
221 }
222
223 /*!
224     Sets the attachment configuration of a framebuffer object to \a attachment.
225
226     \sa attachment()
227 */
228 void QOpenGLFramebufferObjectFormat::setAttachment(QOpenGLFramebufferObject::Attachment attachment)
229 {
230     detach();
231     d->attachment = attachment;
232 }
233
234 /*!
235     Returns the configuration of the depth and stencil buffers attached to
236     a framebuffer object.  The default is QOpenGLFramebufferObject::NoAttachment.
237
238     \sa setAttachment()
239 */
240 QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObjectFormat::attachment() const
241 {
242     return d->attachment;
243 }
244
245 /*!
246     Sets the texture target of the texture attached to a framebuffer object to
247     \a target. Ignored for multisample framebuffer objects.
248
249     \sa textureTarget(), samples()
250 */
251 void QOpenGLFramebufferObjectFormat::setTextureTarget(GLenum target)
252 {
253     detach();
254     d->target = target;
255 }
256
257 /*!
258     Returns the texture target of the texture attached to a framebuffer object.
259     Ignored for multisample framebuffer objects.  The default is
260     \c GL_TEXTURE_2D.
261
262     \sa setTextureTarget(), samples()
263 */
264 GLenum QOpenGLFramebufferObjectFormat::textureTarget() const
265 {
266     return d->target;
267 }
268
269 /*!
270     Sets the internal format of a framebuffer object's texture or
271     multisample framebuffer object's color buffer to
272     \a internalTextureFormat.
273
274     \sa internalTextureFormat()
275 */
276 void QOpenGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
277 {
278     detach();
279     d->internal_format = internalTextureFormat;
280 }
281
282 /*!
283     Returns the internal format of a framebuffer object's texture or
284     multisample framebuffer object's color buffer.  The default is
285     \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on
286     OpenGL/ES systems.
287
288     \sa setInternalTextureFormat()
289 */
290 GLenum QOpenGLFramebufferObjectFormat::internalTextureFormat() const
291 {
292     return d->internal_format;
293 }
294
295 /*!
296     Returns true if all the options of this framebuffer object format
297     are the same as \a other; otherwise returns false.
298 */
299 bool QOpenGLFramebufferObjectFormat::operator==(const QOpenGLFramebufferObjectFormat& other) const
300 {
301     if (d == other.d)
302         return true;
303     else
304         return d->equals(other.d);
305 }
306
307 /*!
308     Returns false if all the options of this framebuffer object format
309     are the same as \a other; otherwise returns true.
310 */
311 bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFormat& other) const
312 {
313     return !(*this == other);
314 }
315
316 bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus(QOpenGLContext *ctx) const
317 {
318     if (!ctx)
319         return false;   // Context no longer exists.
320     GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);
321     switch(status) {
322     case GL_NO_ERROR:
323     case GL_FRAMEBUFFER_COMPLETE:
324         return true;
325         break;
326     case GL_FRAMEBUFFER_UNSUPPORTED:
327         qDebug("QOpenGLFramebufferObject: Unsupported framebuffer format.");
328         break;
329     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
330         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete attachment.");
331         break;
332     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
333         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment.");
334         break;
335 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT
336     case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT:
337         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
338         break;
339 #endif
340     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
341         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
342         break;
343     case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
344         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
345         break;
346     case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
347         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
348         break;
349     case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
350         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
351         break;
352     case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
353         qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
354         break;
355     default:
356         qDebug() <<"QOpenGLFramebufferObject: An undefined error has occurred: "<< status;
357         break;
358     }
359     return false;
360 }
361
362 namespace
363 {
364     void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)
365     {
366         funcs->glDeleteFramebuffers(1, &id);
367     }
368
369     void freeRenderbufferFunc(QOpenGLFunctions *funcs, GLuint id)
370     {
371         funcs->glDeleteRenderbuffers(1, &id);
372     }
373
374     void freeTextureFunc(QOpenGLFunctions *, GLuint id)
375     {
376         glDeleteTextures(1, &id);
377     }
378 }
379
380 void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSize &sz,
381                                        QOpenGLFramebufferObject::Attachment attachment,
382                                        GLenum texture_target, GLenum internal_format,
383                                        GLint samples, bool mipmap)
384 {
385     QOpenGLContext *ctx = QOpenGLContext::currentContext();
386
387     funcs.initializeGLFunctions();
388
389     if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers))
390         return;
391
392     size = sz;
393     target = texture_target;
394     // texture dimensions
395
396     QT_RESET_GLERROR(); // reset error state
397     GLuint fbo = 0;
398
399     funcs.glGenFramebuffers(1, &fbo);
400     funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo);
401
402     GLuint texture = 0;
403     GLuint color_buffer = 0;
404
405     QT_CHECK_GLERROR();
406     // init texture
407     if (samples == 0) {
408         glGenTextures(1, &texture);
409         glBindTexture(target, texture);
410         glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
411                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
412         if (mipmap) {
413             int width = size.width();
414             int height = size.height();
415             int level = 0;
416             while (width > 1 || height > 1) {
417                 width = (width + 1) >> 1;
418                 height = (height + 1) >> 1;
419                 ++level;
420                 glTexImage2D(target, level, internal_format, width, height, 0,
421                         GL_RGBA, GL_UNSIGNED_BYTE, NULL);
422             }
423         }
424         glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
425         glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
426         glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
427         glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
428         funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
429                 target, texture, 0);
430
431         QT_CHECK_GLERROR();
432         valid = checkFramebufferStatus(ctx);
433         glBindTexture(target, 0);
434
435         color_buffer = 0;
436     } else {
437         mipmap = false;
438         GLint maxSamples;
439         glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
440
441         samples = qBound(0, int(samples), int(maxSamples));
442
443         funcs.glGenRenderbuffers(1, &color_buffer);
444         funcs.glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);
445         if (funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) && samples > 0) {
446             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
447                 internal_format, size.width(), size.height());
448         } else {
449             samples = 0;
450             funcs.glRenderbufferStorage(GL_RENDERBUFFER, internal_format,
451                 size.width(), size.height());
452         }
453
454         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
455                                              GL_RENDERBUFFER, color_buffer);
456
457         QT_CHECK_GLERROR();
458         valid = checkFramebufferStatus(ctx);
459
460         if (valid)
461             funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
462     }
463
464     format.setTextureTarget(target);
465     format.setSamples(int(samples));
466     format.setInternalTextureFormat(internal_format);
467     format.setMipmap(mipmap);
468
469     initAttachments(ctx, attachment);
470
471     funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
472     if (valid) {
473         fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
474         if (color_buffer)
475             color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
476         else
477             texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
478     } else {
479         if (color_buffer)
480             funcs.glDeleteRenderbuffers(1, &color_buffer);
481         else
482             glDeleteTextures(1, &texture);
483         funcs.glDeleteFramebuffers(1, &fbo);
484     }
485     QT_CHECK_GLERROR();
486 }
487
488 void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment)
489 {
490     int samples = format.samples();
491
492     // free existing attachments
493     if (depth_buffer_guard) {
494         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
495         depth_buffer_guard->free();
496     }
497     if (stencil_buffer_guard) {
498         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
499         if (stencil_buffer_guard != depth_buffer_guard)
500             stencil_buffer_guard->free();
501     }
502
503     depth_buffer_guard = 0;
504     stencil_buffer_guard = 0;
505
506     GLuint depth_buffer = 0;
507     GLuint stencil_buffer = 0;
508
509     // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
510     // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
511     // might not be supported while separate buffers are, according to QTBUG-12861.
512
513     if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
514         && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
515     {
516         // depth and stencil buffer needs another extension
517         funcs.glGenRenderbuffers(1, &depth_buffer);
518         funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
519         Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
520         if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
521             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
522                 GL_DEPTH24_STENCIL8, size.width(), size.height());
523         else
524             funcs.glRenderbufferStorage(GL_RENDERBUFFER,
525                 GL_DEPTH24_STENCIL8, size.width(), size.height());
526
527         stencil_buffer = depth_buffer;
528         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
529                                      GL_RENDERBUFFER, depth_buffer);
530         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
531                                      GL_RENDERBUFFER, stencil_buffer);
532
533         valid = checkFramebufferStatus(ctx);
534         if (!valid) {
535             funcs.glDeleteRenderbuffers(1, &depth_buffer);
536             stencil_buffer = depth_buffer = 0;
537         }
538     }
539
540     if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
541         || (attachment == QOpenGLFramebufferObject::Depth)))
542     {
543         funcs.glGenRenderbuffers(1, &depth_buffer);
544         funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
545         Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
546         if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
547 #ifdef QT_OPENGL_ES
548             if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
549                 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
550                     GL_DEPTH_COMPONENT24, size.width(), size.height());
551             } else {
552                 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
553                     GL_DEPTH_COMPONENT16, size.width(), size.height());
554             }
555 #else
556             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
557                 GL_DEPTH_COMPONENT, size.width(), size.height());
558 #endif
559         } else {
560 #ifdef QT_OPENGL_ES
561             if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
562                 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24,
563                                         size.width(), size.height());
564             } else {
565                 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
566                                         size.width(), size.height());
567             }
568 #else
569             funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height());
570 #endif
571         }
572         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
573                                      GL_RENDERBUFFER, depth_buffer);
574         valid = checkFramebufferStatus(ctx);
575         if (!valid) {
576             funcs.glDeleteRenderbuffers(1, &depth_buffer);
577             depth_buffer = 0;
578         }
579     }
580
581     if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) {
582         funcs.glGenRenderbuffers(1, &stencil_buffer);
583         funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer);
584         Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer));
585         if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
586 #ifdef QT_OPENGL_ES
587             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
588                 GL_STENCIL_INDEX8, size.width(), size.height());
589 #else
590             funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
591                 GL_STENCIL_INDEX, size.width(), size.height());
592 #endif
593         } else {
594 #ifdef QT_OPENGL_ES
595             funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
596                                   size.width(), size.height());
597 #else
598             funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX,
599                                   size.width(), size.height());
600 #endif
601         }
602         funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
603                                   GL_RENDERBUFFER, stencil_buffer);
604         valid = checkFramebufferStatus(ctx);
605         if (!valid) {
606             funcs.glDeleteRenderbuffers(1, &stencil_buffer);
607             stencil_buffer = 0;
608         }
609     }
610
611     // The FBO might have become valid after removing the depth or stencil buffer.
612     valid = checkFramebufferStatus(ctx);
613
614     if (depth_buffer && stencil_buffer) {
615         fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
616     } else if (depth_buffer) {
617         fbo_attachment = QOpenGLFramebufferObject::Depth;
618     } else {
619         fbo_attachment = QOpenGLFramebufferObject::NoAttachment;
620     }
621
622     if (valid) {
623         if (depth_buffer)
624             depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
625         if (stencil_buffer) {
626             if (stencil_buffer == depth_buffer)
627                 stencil_buffer_guard = depth_buffer_guard;
628             else
629                 stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
630         }
631     } else {
632         if (depth_buffer)
633             funcs.glDeleteRenderbuffers(1, &depth_buffer);
634         if (stencil_buffer && depth_buffer != stencil_buffer)
635             funcs.glDeleteRenderbuffers(1, &stencil_buffer);
636     }
637     QT_CHECK_GLERROR();
638
639     format.setAttachment(fbo_attachment);
640 }
641
642 /*!
643     \class QOpenGLFramebufferObject
644     \brief The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer object.
645     \since 5.0
646
647     \ingroup painting-3D
648
649     The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer
650     object, defined by the \c{GL_EXT_framebuffer_object} extension. In
651     addition it provides a rendering surface that can be painted on
652     with a QPainter, rendered to using native GL calls, or both. This
653     surface can be bound and used as a regular texture in your own GL
654     drawing code.  By default, the QOpenGLFramebufferObject class
655     generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
656     which is used as the internal rendering target.
657
658     \bold{It is important to have a current GL context when creating a
659     QOpenGLFramebufferObject, otherwise initialization will fail.}
660
661     When using a QPainter to paint to a QOpenGLFramebufferObject you should take
662     care that the QOpenGLFramebufferObject is created with the CombinedDepthStencil
663     attachment for QPainter to be able to render correctly.
664     Note that you need to create a QOpenGLFramebufferObject with more than one
665     sample per pixel for primitives to be antialiased when drawing using a
666     QPainter. To create a multisample framebuffer object you should use one of
667     the constructors that take a QOpenGLFramebufferObject parameter, and set the
668     QOpenGLFramebufferObject::samples() property to a non-zero value.
669
670     For multisample framebuffer objects a color render buffer is created,
671     otherwise a texture with the specified texture target is created.
672     The color render buffer or texture will have the specified internal
673     format, and will be bound to the \c GL_COLOR_ATTACHMENT0
674     attachment in the framebuffer object.
675
676     If you want to use a framebuffer object with multisampling enabled
677     as a texture, you first need to copy from it to a regular framebuffer
678     object using QOpenGLContext::blitFramebuffer().
679
680     \section1 Threading
681
682     As of Qt 4.8, it's possible to draw into a QOpenGLFramebufferObject
683     using a QPainter in a separate thread. Note that OpenGL 2.0 or
684     OpenGL ES 2.0 is required for this to work.
685 */
686
687
688 /*!
689     \enum QOpenGLFramebufferObject::Attachment
690
691     This enum type is used to configure the depth and stencil buffers
692     attached to the framebuffer object when it is created.
693
694     \value NoAttachment         No attachment is added to the framebuffer object. Note that the
695                                 OpenGL depth and stencil tests won't work when rendering to a
696                                 framebuffer object without any depth or stencil buffers.
697                                 This is the default value.
698
699     \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
700                                 a combined depth and stencil buffer is attached.
701                                 If the extension is not present, only a depth buffer is attached.
702
703     \value Depth                A depth buffer is attached to the framebuffer object.
704
705     \sa attachment()
706 */
707
708
709 /*! \fn QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target)
710
711     Constructs an OpenGL framebuffer object and binds a 2D GL texture
712     to the buffer of the size \a size. The texture is bound to the
713     \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
714
715     The \a target parameter is used to specify the GL texture
716     target. The default target is \c GL_TEXTURE_2D. Keep in mind that
717     \c GL_TEXTURE_2D textures must have a power of 2 width and height
718     (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
719
720     By default, no depth and stencil buffers are attached. This behavior
721     can be toggled using one of the overloaded constructors.
722
723     The default internal texture format is \c GL_RGBA8 for desktop
724     OpenGL, and \c GL_RGBA for OpenGL/ES.
725
726     It is important that you have a current GL context set when
727     creating the QOpenGLFramebufferObject, otherwise the initialization
728     will fail.
729
730     \sa size(), texture(), attachment()
731 */
732
733 QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target)
734     : d_ptr(new QOpenGLFramebufferObjectPrivate)
735 {
736     Q_D(QOpenGLFramebufferObject);
737     d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
738 }
739
740 /*! \overload
741
742     Constructs an OpenGL framebuffer object and binds a 2D GL texture
743     to the buffer of the given \a width and \a height.
744
745     \sa size(), texture()
746 */
747 QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, GLenum target)
748     : d_ptr(new QOpenGLFramebufferObjectPrivate)
749 {
750     Q_D(QOpenGLFramebufferObject);
751     d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
752 }
753
754 /*! \overload
755
756     Constructs an OpenGL framebuffer object of the given \a size based on the
757     supplied \a format.
758 */
759
760 QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format)
761     : d_ptr(new QOpenGLFramebufferObjectPrivate)
762 {
763     Q_D(QOpenGLFramebufferObject);
764     d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
765             format.samples(), format.mipmap());
766 }
767
768 /*! \overload
769
770     Constructs an OpenGL framebuffer object of the given \a width and \a height
771     based on the supplied \a format.
772 */
773
774 QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format)
775     : d_ptr(new QOpenGLFramebufferObjectPrivate)
776 {
777     Q_D(QOpenGLFramebufferObject);
778     d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
779             format.internalTextureFormat(), format.samples(), format.mipmap());
780 }
781
782 /*! \overload
783
784     Constructs an OpenGL framebuffer object and binds a texture to the
785     buffer of the given \a width and \a height.
786
787     The \a attachment parameter describes the depth/stencil buffer
788     configuration, \a target the texture target and \a internal_format
789     the internal texture format. The default texture target is \c
790     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
791     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
792
793     \sa size(), texture(), attachment()
794 */
795 QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, Attachment attachment,
796                                            GLenum target, GLenum internal_format)
797     : d_ptr(new QOpenGLFramebufferObjectPrivate)
798 {
799     Q_D(QOpenGLFramebufferObject);
800     d->init(this, QSize(width, height), attachment, target, internal_format);
801 }
802
803 /*! \overload
804
805     Constructs an OpenGL framebuffer object and binds a texture to the
806     buffer of the given \a size.
807
808     The \a attachment parameter describes the depth/stencil buffer
809     configuration, \a target the texture target and \a internal_format
810     the internal texture format. The default texture target is \c
811     GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
812     for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
813
814     \sa size(), texture(), attachment()
815 */
816 QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, Attachment attachment,
817                                            GLenum target, GLenum internal_format)
818     : d_ptr(new QOpenGLFramebufferObjectPrivate)
819 {
820     Q_D(QOpenGLFramebufferObject);
821     d->init(this, size, attachment, target, internal_format);
822 }
823
824 /*!
825     \fn QOpenGLFramebufferObject::~QOpenGLFramebufferObject()
826
827     Destroys the framebuffer object and frees any allocated resources.
828 */
829 QOpenGLFramebufferObject::~QOpenGLFramebufferObject()
830 {
831     Q_D(QOpenGLFramebufferObject);
832
833     if (d->texture_guard)
834         d->texture_guard->free();
835     if (d->color_buffer_guard)
836         d->color_buffer_guard->free();
837     if (d->depth_buffer_guard)
838         d->depth_buffer_guard->free();
839     if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
840         d->stencil_buffer_guard->free();
841     if (d->fbo_guard)
842         d->fbo_guard->free();
843 }
844
845 /*!
846     \fn bool QOpenGLFramebufferObject::isValid() const
847
848     Returns true if the framebuffer object is valid.
849
850     The framebuffer can become invalid if the initialization process
851     fails, the user attaches an invalid buffer to the framebuffer
852     object, or a non-power of two width/height is specified as the
853     texture size if the texture target is \c{GL_TEXTURE_2D}.
854     The non-power of two limitation does not apply if the OpenGL version
855     is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
856     is present.
857
858     The framebuffer can also become invalid if the QOpenGLContext that
859     the framebuffer was created within is destroyed and there are
860     no other shared contexts that can take over ownership of the
861     framebuffer.
862 */
863 bool QOpenGLFramebufferObject::isValid() const
864 {
865     Q_D(const QOpenGLFramebufferObject);
866     return d->valid && d->fbo_guard && d->fbo_guard->id();
867 }
868
869 /*!
870     \fn bool QOpenGLFramebufferObject::bind()
871
872     Switches rendering from the default, windowing system provided
873     framebuffer to this framebuffer object.
874     Returns true upon success, false otherwise.
875
876     \sa release()
877 */
878 bool QOpenGLFramebufferObject::bind()
879 {
880     if (!isValid())
881         return false;
882     Q_D(QOpenGLFramebufferObject);
883     QOpenGLContext *current = QOpenGLContext::currentContext();
884     if (!current)
885         return false;
886 #ifdef QT_DEBUG
887     if (current->shareGroup() != d->fbo_guard->group())
888         qWarning("QOpenGLFramebufferObject::bind() called from incompatible context");
889 #endif
890     d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
891     d->valid = d->checkFramebufferStatus(current);
892     if (d->valid && current)
893         current->d_func()->current_fbo = d->fbo();
894     return d->valid;
895 }
896
897 /*!
898     \fn bool QOpenGLFramebufferObject::release()
899
900     Switches rendering back to the default, windowing system provided
901     framebuffer.
902     Returns true upon success, false otherwise.
903
904     \sa bind()
905 */
906 bool QOpenGLFramebufferObject::release()
907 {
908     if (!isValid())
909         return false;
910
911     QOpenGLContext *current = QOpenGLContext::currentContext();
912     if (!current)
913         return false;
914
915     Q_D(QOpenGLFramebufferObject);
916 #ifdef QT_DEBUG
917     if (current->shareGroup() != d->fbo_guard->group())
918         qWarning("QOpenGLFramebufferObject::release() called from incompatible context");
919 #endif
920
921     if (current) {
922         current->d_func()->current_fbo = current->defaultFramebufferObject();
923         d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->current_fbo);
924     }
925
926     return true;
927 }
928
929 /*!
930     \fn GLuint QOpenGLFramebufferObject::texture() const
931
932     Returns the texture id for the texture attached as the default
933     rendering target in this framebuffer object. This texture id can
934     be bound as a normal texture in your own GL code.
935
936     If a multisample framebuffer object is used then the value returned
937     from this function will be invalid.
938 */
939 GLuint QOpenGLFramebufferObject::texture() const
940 {
941     Q_D(const QOpenGLFramebufferObject);
942     return d->texture_guard ? d->texture_guard->id() : 0;
943 }
944
945 /*!
946     \fn QSize QOpenGLFramebufferObject::size() const
947
948     Returns the size of the texture attached to this framebuffer
949     object.
950 */
951 QSize QOpenGLFramebufferObject::size() const
952 {
953     Q_D(const QOpenGLFramebufferObject);
954     return d->size;
955 }
956
957 /*!
958     \fn int QOpenGLFramebufferObject::width() const
959
960     Returns the width of the framebuffer object attachments.
961 */
962
963 /*!
964     \fn int QOpenGLFramebufferObject::height() const
965
966     Returns the height of the framebuffer object attachments.
967 */
968
969 /*!
970     Returns the format of this framebuffer object.
971 */
972 QOpenGLFramebufferObjectFormat QOpenGLFramebufferObject::format() const
973 {
974     Q_D(const QOpenGLFramebufferObject);
975     return d->format;
976 }
977
978 namespace {
979 /*
980    Read back the contents of the currently bound framebuffer, used in
981    QGLWidget::grabFrameBuffer(), QGLPixelbuffer::toImage() and
982    QGLFramebufferObject::toImage()
983 */
984
985 void convertFromGLImage(QImage &img, int w, int h, bool alpha_format, bool include_alpha)
986 {
987     if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
988         // OpenGL gives RGBA; Qt wants ARGB
989         uint *p = (uint*)img.bits();
990         uint *end = p + w*h;
991         if (alpha_format && include_alpha) {
992             while (p < end) {
993                 uint a = *p << 24;
994                 *p = (*p >> 8) | a;
995                 p++;
996             }
997         } else {
998             // This is an old legacy fix for PowerPC based Macs, which
999             // we shouldn't remove
1000             while (p < end) {
1001                 *p = 0xff000000 | (*p>>8);
1002                 ++p;
1003             }
1004         }
1005     } else {
1006         // OpenGL gives ABGR (i.e. RGBA backwards); Qt wants ARGB
1007         for (int y = 0; y < h; y++) {
1008             uint *q = (uint*)img.scanLine(y);
1009             for (int x=0; x < w; ++x) {
1010                 const uint pixel = *q;
1011                 if (alpha_format && include_alpha) {
1012                     *q = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff)
1013                          | (pixel & 0xff00ff00);
1014                 } else {
1015                     *q = 0xff000000 | ((pixel << 16) & 0xff0000)
1016                          | ((pixel >> 16) & 0xff) | (pixel & 0x00ff00);
1017                 }
1018
1019                 q++;
1020             }
1021         }
1022
1023     }
1024     img = img.mirrored();
1025 }
1026
1027 }
1028
1029 Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha)
1030 {
1031     QImage img(size, (alpha_format && include_alpha) ? QImage::Format_ARGB32_Premultiplied
1032                                                      : QImage::Format_RGB32);
1033     int w = size.width();
1034     int h = size.height();
1035     glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
1036     convertFromGLImage(img, w, h, alpha_format, include_alpha);
1037     return img;
1038 }
1039
1040 /*!
1041     \fn QImage QOpenGLFramebufferObject::toImage() const
1042
1043     Returns the contents of this framebuffer object as a QImage.
1044 */
1045 QImage QOpenGLFramebufferObject::toImage() const
1046 {
1047     Q_D(const QOpenGLFramebufferObject);
1048     if (!d->valid)
1049         return QImage();
1050
1051     // qt_gl_read_framebuffer doesn't work on a multisample FBO
1052     if (format().samples() != 0) {
1053         QOpenGLFramebufferObject temp(size(), QOpenGLFramebufferObjectFormat());
1054
1055         QRect rect(QPoint(0, 0), size());
1056         blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect);
1057
1058         return temp.toImage();
1059     }
1060
1061     bool wasBound = isBound();
1062     if (!wasBound)
1063         const_cast<QOpenGLFramebufferObject *>(this)->bind();
1064     QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
1065     if (!wasBound)
1066         const_cast<QOpenGLFramebufferObject *>(this)->release();
1067
1068     return image;
1069 }
1070
1071 /*!
1072     \fn bool QOpenGLFramebufferObject::bindDefault()
1073     \internal
1074
1075     Switches rendering back to the default, windowing system provided
1076     framebuffer.
1077     Returns true upon success, false otherwise.
1078
1079     \sa bind(), release()
1080 */
1081 bool QOpenGLFramebufferObject::bindDefault()
1082 {
1083     QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
1084     QOpenGLFunctions functions(ctx);
1085
1086     if (ctx) {
1087         ctx->d_func()->current_fbo = ctx->defaultFramebufferObject();
1088         functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
1089 #ifdef QT_DEBUG
1090     } else {
1091         qWarning("QOpenGLFramebufferObject::bindDefault() called without current context.");
1092 #endif
1093     }
1094
1095     return ctx != 0;
1096 }
1097
1098 /*!
1099     \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()
1100
1101     Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
1102     is present on this system; otherwise returns false.
1103 */
1104 bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects()
1105 {
1106     return QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::Framebuffers);
1107 }
1108
1109 /*!
1110     \fn GLuint QOpenGLFramebufferObject::handle() const
1111
1112     Returns the GL framebuffer object handle for this framebuffer
1113     object (returned by the \c{glGenFrameBuffersEXT()} function). This
1114     handle can be used to attach new images or buffers to the
1115     framebuffer. The user is responsible for cleaning up and
1116     destroying these objects.
1117 */
1118 GLuint QOpenGLFramebufferObject::handle() const
1119 {
1120     Q_D(const QOpenGLFramebufferObject);
1121     return d->fbo();
1122 }
1123
1124 /*!
1125     Returns the status of the depth and stencil buffers attached to
1126     this framebuffer object.
1127 */
1128
1129 QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() const
1130 {
1131     Q_D(const QOpenGLFramebufferObject);
1132     if (d->valid)
1133         return d->fbo_attachment;
1134     return NoAttachment;
1135 }
1136
1137 /*!
1138     Sets the attachments of the framebuffer object.
1139
1140     This can be used to free or reattach the depth and stencil buffer
1141     attachments as needed.
1142  */
1143 void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment)
1144 {
1145     Q_D(QOpenGLFramebufferObject);
1146     if (attachment == d->fbo_attachment || !isValid())
1147         return;
1148     QOpenGLContext *current = QOpenGLContext::currentContext();
1149     if (!current)
1150         return;
1151 #ifdef QT_DEBUG
1152     if (current->shareGroup() != d->fbo_guard->group())
1153         qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");
1154 #endif
1155     d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
1156     d->initAttachments(current, attachment);
1157     if (current->d_func()->current_fbo != d->fbo())
1158         d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->current_fbo);
1159 }
1160
1161 /*!
1162     Returns true if the framebuffer object is currently bound to a context,
1163     otherwise false is returned.
1164 */
1165
1166 bool QOpenGLFramebufferObject::isBound() const
1167 {
1168     Q_D(const QOpenGLFramebufferObject);
1169     QOpenGLContext *current = QOpenGLContext::currentContext();
1170     return current ? current->d_func()->current_fbo == d->fbo() : false;
1171 }
1172
1173 /*!
1174     \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()
1175
1176     Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
1177     is present on this system; otherwise returns false.
1178
1179     \sa blitFramebuffer()
1180 */
1181 bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()
1182 {
1183     return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit);
1184 }
1185
1186
1187 /*!
1188     \overload
1189
1190     Convenience overload to blit between two framebuffer objects.
1191 */
1192 void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
1193                                                QOpenGLFramebufferObject *source,
1194                                                GLbitfield buffers, GLenum filter)
1195 {
1196     if (!target && !source)
1197         return;
1198
1199     QSize targetSize;
1200     QSize sourceSize;
1201
1202     if (target)
1203         targetSize = target->size();
1204     if (source)
1205         sourceSize = source->size();
1206
1207     if (targetSize.isEmpty())
1208         targetSize = sourceSize;
1209     else if (sourceSize.isEmpty())
1210         sourceSize = targetSize;
1211
1212     blitFramebuffer(target, QRect(QPoint(0, 0), targetSize),
1213                     source, QRect(QPoint(0, 0), sourceSize),
1214                     buffers, filter);
1215 }
1216
1217 /*!
1218     Blits from the \a sourceRect rectangle in the \a source framebuffer
1219     object to the \a targetRect rectangle in the \a target framebuffer object.
1220
1221     If \a source or \a target is 0, the default framebuffer will be used
1222     instead of a framebuffer object as source or target respectively.
1223
1224     The \a buffers parameter should be a mask consisting of any combination of
1225     \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
1226     \c GL_STENCIL_BUFFER_BIT.  Any buffer type that is not present both
1227     in the source and target buffers is ignored.
1228
1229     The \a sourceRect and \a targetRect rectangles may have different sizes;
1230     in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
1231     \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
1232     \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
1233     interpolation should be used when scaling is performed.
1234
1235     If \a source equals \a target a copy is performed within the same buffer.
1236     Results are undefined if the source and target rectangles overlap and
1237     have different sizes. The sizes must also be the same if any of the
1238     framebuffer objects are multisample framebuffers.
1239
1240     Note that the scissor test will restrict the blit area if enabled.
1241
1242     This function will have no effect unless hasOpenGLFramebufferBlit() returns
1243     true.
1244
1245     \sa hasOpenGLFramebufferBlit()
1246 */
1247 void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect,
1248                                            QOpenGLFramebufferObject *source, const QRect &sourceRect,
1249                                            GLbitfield buffers,
1250                                            GLenum filter)
1251 {
1252     QOpenGLContext *ctx = QOpenGLContext::currentContext();
1253     if (!ctx)
1254         return;
1255
1256     QOpenGLExtensions extensions(ctx);
1257     if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
1258         return;
1259
1260     const int sx0 = sourceRect.left();
1261     const int sx1 = sourceRect.left() + sourceRect.width();
1262     const int sy0 = sourceRect.top();
1263     const int sy1 = sourceRect.top() + sourceRect.height();
1264
1265     const int tx0 = targetRect.left();
1266     const int tx1 = targetRect.left() + targetRect.width();
1267     const int ty0 = targetRect.top();
1268     const int ty1 = targetRect.top() + targetRect.height();
1269
1270     extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0);
1271     extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0);
1272
1273     extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
1274                                  tx0, ty0, tx1, ty1,
1275                                  buffers, filter);
1276
1277     extensions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
1278 }
1279
1280 QT_END_NAMESPACE