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