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