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