1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtOpenGL module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qglframebufferobject.h"
43 #include "qglframebufferobject_p.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>
52 #ifndef QT_OPENGL_ES_2
53 #include <private/qpaintengine_opengl_p.h>
56 #include <qglframebufferobject.h>
62 extern Q_OPENGL_EXPORT QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
64 #define QGL_FUNC_CONTEXT const QGLContext *ctx = d_ptr->fbo_guard.context();
65 #define QGL_FUNCP_CONTEXT const QGLContext *ctx = fbo_guard.context();
68 #define QT_RESET_GLERROR() \
70 while (glGetError() != GL_NO_ERROR) {} \
72 #define QT_CHECK_GLERROR() \
74 GLenum err = glGetError(); \
75 if (err != GL_NO_ERROR) { \
76 qDebug("[%s line %d] GL Error: %d", \
77 __FILE__, __LINE__, (int)err); \
81 #define QT_RESET_GLERROR() {}
82 #define QT_CHECK_GLERROR() {}
86 \class QGLFramebufferObjectFormat
87 \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
94 A framebuffer object has several characteristics:
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
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.
107 \sa QGLFramebufferObject
113 void QGLFramebufferObjectFormat::detach()
116 QGLFramebufferObjectFormatPrivate *newd
117 = new QGLFramebufferObjectFormatPrivate(d);
125 Creates a QGLFramebufferObjectFormat object for specifying
126 the format of an OpenGL framebuffer object.
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.
132 \sa samples(), attachment(), internalTextureFormat()
135 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
137 d = new QGLFramebufferObjectFormatPrivate;
141 Constructs a copy of \a other.
144 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
151 Assigns \a other to this object.
154 QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
166 Destroys the QGLFramebufferObjectFormat.
168 QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
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.
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.
187 void QGLFramebufferObjectFormat::setSamples(int samples)
190 d->samples = samples;
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.
200 int QGLFramebufferObjectFormat::samples() const
208 Enables mipmapping if \a enabled is true; otherwise disables it.
210 Mipmapping is disabled by default.
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.
217 \sa mipmap(), QGLFramebufferObject::texture()
219 void QGLFramebufferObjectFormat::setMipmap(bool enabled)
228 Returns true if mipmapping is enabled.
232 bool QGLFramebufferObjectFormat::mipmap() const
238 Sets the attachment configuration of a framebuffer object to \a attachment.
242 void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
245 d->attachment = attachment;
249 Returns the configuration of the depth and stencil buffers attached to
250 a framebuffer object. The default is QGLFramebufferObject::NoAttachment.
254 QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
256 return d->attachment;
260 Sets the texture target of the texture attached to a framebuffer object to
261 \a target. Ignored for multisample framebuffer objects.
263 \sa textureTarget(), samples()
265 void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
272 Returns the texture target of the texture attached to a framebuffer object.
273 Ignored for multisample framebuffer objects. The default is
276 \sa setTextureTarget(), samples()
278 GLenum QGLFramebufferObjectFormat::textureTarget() const
284 Sets the internal format of a framebuffer object's texture or
285 multisample framebuffer object's color buffer to
286 \a internalTextureFormat.
288 \sa internalTextureFormat()
290 void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
293 d->internal_format = internalTextureFormat;
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
302 \sa setInternalTextureFormat()
304 GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
306 return d->internal_format;
309 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
311 void QGLFramebufferObjectFormat::setTextureTarget(QMacCompatGLenum target)
318 void QGLFramebufferObjectFormat::setInternalTextureFormat(QMacCompatGLenum internalTextureFormat)
321 d->internal_format = internalTextureFormat;
326 Returns true if all the options of this framebuffer object format
327 are the same as \a other; otherwise returns false.
329 bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
334 return d->equals(other.d);
338 Returns false if all the options of this framebuffer object format
339 are the same as \a other; otherwise returns true.
341 bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
343 return !(*this == other);
346 void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
347 QGLFramebufferObject::Attachment attachment)
350 m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
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);
362 fboFormat.setDepth(false);
363 fboFormat.setStencil(false);
366 GLenum format = f->format().internalTextureFormat();
367 reqAlpha = (format != GL_RGB
369 && format != GL_RGB5 && format != GL_RGB8
374 QGLContext *QGLFBOGLPaintDevice::context() const
376 QGLContext *fboContext = const_cast<QGLContext *>(fbo->d_ptr->fbo_guard.context());
377 QGLContext *currentContext = const_cast<QGLContext *>(QGLContext::currentContext());
379 if (QGLContextPrivate::contextGroup(fboContext) == QGLContextPrivate::contextGroup(currentContext))
380 return currentContext;
385 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
389 return false; // Context no longer exists.
390 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
393 case GL_FRAMEBUFFER_COMPLETE_EXT:
396 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
397 qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
399 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
400 qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
402 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
403 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
405 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
406 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
407 qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
410 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
411 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
413 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
414 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
416 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
417 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
419 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
420 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
422 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
423 qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
426 qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
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)
437 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
438 fbo_guard.setContext(ctx);
440 bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
441 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
445 target = texture_target;
446 // texture dimensions
448 QT_RESET_GLERROR(); // reset error state
450 glGenFramebuffers(1, &fbo);
451 glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
452 fbo_guard.setId(fbo);
454 glDevice.setFBO(q, attachment);
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);
464 glGenerateMipmap(GL_TEXTURE_2D);
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);
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);
476 glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
480 valid = checkFramebufferStatus();
481 glBindTexture(target, 0);
487 glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples);
489 samples = qBound(0, int(samples), int(maxSamples));
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());
498 glRenderbufferStorage(GL_RENDERBUFFER_EXT, internal_format,
499 size.width(), size.height());
502 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
503 GL_RENDERBUFFER_EXT, color_buffer);
506 valid = checkFramebufferStatus();
509 glGetRenderbufferParameteriv(GL_RENDERBUFFER_EXT, GL_RENDERBUFFER_SAMPLES_EXT, &samples);
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.
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());
527 glRenderbufferStorage(GL_RENDERBUFFER_EXT,
528 GL_DEPTH24_STENCIL8_EXT, size.width(), size.height());
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);
536 valid = checkFramebufferStatus();
538 glDeleteRenderbuffers(1, &depth_buffer);
539 stencil_buffer = depth_buffer = 0;
543 if (depth_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil
544 || (attachment == QGLFramebufferObject::Depth)))
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) {
552 if (QGLExtensions::glExtensions() & QGLExtensions::Depth24) {
553 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
554 GL_DEPTH_COMPONENT24_OES, size.width(), size.height());
556 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
557 GL_DEPTH_COMPONENT16, size.width(), size.height());
560 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
561 GL_DEPTH_COMPONENT, size.width(), size.height());
565 if (QGLExtensions::glExtensions() & QGLExtensions::Depth24) {
566 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_OES,
567 size.width(), size.height());
569 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16,
570 size.width(), size.height());
573 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, size.width(), size.height());
576 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
577 GL_RENDERBUFFER_EXT, depth_buffer);
578 valid = checkFramebufferStatus();
580 glDeleteRenderbuffers(1, &depth_buffer);
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) {
592 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
593 GL_STENCIL_INDEX8_EXT, size.width(), size.height());
595 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, samples,
596 GL_STENCIL_INDEX, size.width(), size.height());
600 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT,
601 size.width(), size.height());
603 glRenderbufferStorage(GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX,
604 size.width(), size.height());
607 glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT,
608 GL_RENDERBUFFER_EXT, stencil_buffer);
609 valid = checkFramebufferStatus();
611 glDeleteRenderbuffers(1, &stencil_buffer);
616 // The FBO might have become valid after removing the depth or stencil buffer.
617 valid = checkFramebufferStatus();
619 if (depth_buffer && stencil_buffer) {
620 fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
621 } else if (depth_buffer) {
622 fbo_attachment = QGLFramebufferObject::Depth;
624 fbo_attachment = QGLFramebufferObject::NoAttachment;
627 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);
630 glDeleteRenderbuffers(1, &color_buffer);
632 glDeleteTextures(1, &texture);
634 glDeleteRenderbuffers(1, &depth_buffer);
635 if (stencil_buffer && depth_buffer != stencil_buffer)
636 glDeleteRenderbuffers(1, &stencil_buffer);
637 glDeleteFramebuffers(1, &fbo);
642 format.setTextureTarget(target);
643 format.setSamples(int(samples));
644 format.setAttachment(fbo_attachment);
645 format.setInternalTextureFormat(internal_format);
646 format.setMipmap(mipmap);
650 \class QGLFramebufferObject
651 \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
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.
665 \bold{It is important to have a current GL context when creating a
666 QGLFramebufferObject, otherwise initialization will fail.}
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:
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
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.
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.
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.
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.
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.
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.
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().
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.
726 \sa {Framebuffer Object Example}
731 \enum QGLFramebufferObject::Attachment
734 This enum type is used to configure the depth and stencil buffers
735 attached to the framebuffer object when it is created.
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.
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.
746 \value Depth A depth buffer is attached to the framebuffer object.
752 /*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
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.
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.
763 By default, no depth and stencil buffers are attached. This behavior
764 can be toggled using one of the overloaded constructors.
766 The default internal texture format is \c GL_RGBA8 for desktop
767 OpenGL, and \c GL_RGBA for OpenGL/ES.
769 It is important that you have a current GL context set when
770 creating the QGLFramebufferObject, otherwise the initialization
773 \sa size(), texture(), attachment()
776 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
777 : d_ptr(new QGLFramebufferObjectPrivate)
779 Q_D(QGLFramebufferObject);
780 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
783 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
785 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, QMacCompatGLenum target)
786 : d_ptr(new QGLFramebufferObjectPrivate)
788 Q_D(QGLFramebufferObject);
789 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
795 Constructs an OpenGL framebuffer object and binds a 2D GL texture
796 to the buffer of the given \a width and \a height.
798 \sa size(), texture()
800 QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
801 : d_ptr(new QGLFramebufferObjectPrivate)
803 Q_D(QGLFramebufferObject);
804 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
809 Constructs an OpenGL framebuffer object of the given \a size based on the
813 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
814 : d_ptr(new QGLFramebufferObjectPrivate)
816 Q_D(QGLFramebufferObject);
817 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
818 format.samples(), format.mipmap());
823 Constructs an OpenGL framebuffer object of the given \a width and \a height
824 based on the supplied \a format.
827 QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
828 : d_ptr(new QGLFramebufferObjectPrivate)
830 Q_D(QGLFramebufferObject);
831 d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
832 format.internalTextureFormat(), format.samples(), format.mipmap());
835 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
837 QGLFramebufferObject::QGLFramebufferObject(int width, int height, QMacCompatGLenum target)
838 : d_ptr(new QGLFramebufferObjectPrivate)
840 Q_D(QGLFramebufferObject);
841 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
847 Constructs an OpenGL framebuffer object and binds a texture to the
848 buffer of the given \a width and \a height.
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.
856 \sa size(), texture(), attachment()
858 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
859 GLenum target, GLenum internal_format)
860 : d_ptr(new QGLFramebufferObjectPrivate)
862 Q_D(QGLFramebufferObject);
863 d->init(this, QSize(width, height), attachment, target, internal_format);
866 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
868 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
869 QMacCompatGLenum target, QMacCompatGLenum internal_format)
870 : d_ptr(new QGLFramebufferObjectPrivate)
872 Q_D(QGLFramebufferObject);
873 d->init(this, QSize(width, height), attachment, target, internal_format);
879 Constructs an OpenGL framebuffer object and binds a texture to the
880 buffer of the given \a size.
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.
888 \sa size(), texture(), attachment()
890 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
891 GLenum target, GLenum internal_format)
892 : d_ptr(new QGLFramebufferObjectPrivate)
894 Q_D(QGLFramebufferObject);
895 d->init(this, size, attachment, target, internal_format);
898 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
900 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
901 QMacCompatGLenum target, QMacCompatGLenum internal_format)
902 : d_ptr(new QGLFramebufferObjectPrivate)
904 Q_D(QGLFramebufferObject);
905 d->init(this, size, attachment, target, internal_format);
910 \fn QGLFramebufferObject::~QGLFramebufferObject()
912 Destroys the framebuffer object and frees any allocated resources.
914 QGLFramebufferObject::~QGLFramebufferObject()
916 Q_D(QGLFramebufferObject);
921 if (isValid() && ctx) {
922 QGLShareContextScope scope(ctx);
924 glDeleteTextures(1, &d->texture);
926 glDeleteRenderbuffers(1, &d->color_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);
937 \fn bool QGLFramebufferObject::isValid() const
939 Returns true if the framebuffer object is valid.
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
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
954 bool QGLFramebufferObject::isValid() const
956 Q_D(const QGLFramebufferObject);
957 return d->valid && d->fbo_guard.context();
961 \fn bool QGLFramebufferObject::bind()
963 Switches rendering from the default, windowing system provided
964 framebuffer to this framebuffer object.
965 Returns true upon success, false otherwise.
969 bool QGLFramebufferObject::bind()
973 Q_D(QGLFramebufferObject);
976 return false; // Context no longer exists.
977 const QGLContext *current = QGLContext::currentContext();
980 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
982 qWarning("QGLFramebufferObject::bind() called from incompatible context");
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();
993 \fn bool QGLFramebufferObject::release()
995 Switches rendering back to the default, windowing system provided
997 Returns true upon success, false otherwise.
1001 bool QGLFramebufferObject::release()
1007 return false; // Context no longer exists.
1009 const QGLContext *current = QGLContext::currentContext();
1013 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
1015 qWarning("QGLFramebufferObject::release() called from incompatible context");
1020 current->d_ptr->current_fbo = current->d_ptr->default_fbo;
1021 glBindFramebuffer(GL_FRAMEBUFFER_EXT, current->d_ptr->default_fbo);
1028 \fn GLuint QGLFramebufferObject::texture() const
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.
1034 If a multisample framebuffer object is used then the value returned
1035 from this function will be invalid.
1037 GLuint QGLFramebufferObject::texture() const
1039 Q_D(const QGLFramebufferObject);
1044 \fn QSize QGLFramebufferObject::size() const
1046 Returns the size of the texture attached to this framebuffer
1049 QSize QGLFramebufferObject::size() const
1051 Q_D(const QGLFramebufferObject);
1056 Returns the format of this framebuffer object.
1058 QGLFramebufferObjectFormat QGLFramebufferObject::format() const
1060 Q_D(const QGLFramebufferObject);
1065 \fn QImage QGLFramebufferObject::toImage() const
1067 Returns the contents of this framebuffer object as a QImage.
1069 QImage QGLFramebufferObject::toImage() const
1071 Q_D(const QGLFramebufferObject);
1075 // qt_gl_read_framebuffer doesn't work on a multisample FBO
1076 if (format().samples() != 0) {
1077 QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
1079 QRect rect(QPoint(0, 0), size());
1080 blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
1082 return temp.toImage();
1085 bool wasBound = isBound();
1087 const_cast<QGLFramebufferObject *>(this)->bind();
1088 QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
1090 const_cast<QGLFramebufferObject *>(this)->release();
1095 #if !defined(QT_OPENGL_ES_1)
1096 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
1099 #ifndef QT_OPENGL_ES_2
1100 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QOpenGLPaintEngine>, qt_buffer_engine)
1104 QPaintEngine *QGLFramebufferObject::paintEngine() const
1106 Q_D(const QGLFramebufferObject);
1110 #if !defined(QT_OPENGL_ES_1)
1111 #if !defined (QT_OPENGL_ES_2)
1112 if (qt_gl_preferGL2Engine()) {
1114 QPaintEngine *engine = qt_buffer_2_engine()->engine();
1115 if (engine->isActive() && engine->paintDevice() != this) {
1116 d->engine = new QGL2PaintEngineEx;
1120 #if !defined (QT_OPENGL_ES_2)
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;
1136 \fn bool QGLFramebufferObject::bindDefault()
1139 Switches rendering back to the default, windowing system provided
1141 Returns true upon success, false otherwise.
1143 \sa bind(), release()
1145 bool QGLFramebufferObject::bindDefault()
1147 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
1150 bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
1151 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
1154 ctx->d_ptr->current_fbo = ctx->d_ptr->default_fbo;
1155 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->default_fbo);
1158 qWarning("QGLFramebufferObject::bindDefault() called without current context.");
1166 \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1168 Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
1169 is present on this system; otherwise returns false.
1171 bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1173 return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
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
1183 The framebuffer object should be bound when calling this function.
1185 Equivalent to the corresponding QGLContext::drawTexture().
1187 void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
1189 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1192 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1194 void QGLFramebufferObject::drawTexture(const QRectF &target, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
1196 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
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.
1206 The framebuffer object should be bound when calling this function.
1208 Equivalent to the corresponding QGLContext::drawTexture().
1210 void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
1212 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1215 #ifdef Q_MAC_COMPAT_GL_FUNCTIONS
1217 void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint textureId, QMacCompatGLenum textureTarget)
1219 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1224 int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
1226 Q_D(const QGLFramebufferObject);
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();
1240 return qRound(w * 1000 / dpmx);
1243 return qRound(h * 1000 / dpmy);
1249 return 32;//d->depth;
1252 return qRound(dpmx * 0.0254);
1255 return qRound(dpmy * 0.0254);
1257 case PdmPhysicalDpiX:
1258 return qRound(dpmx * 0.0254);
1260 case PdmPhysicalDpiY:
1261 return qRound(dpmy * 0.0254);
1264 qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
1271 \fn GLuint QGLFramebufferObject::handle() const
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.
1279 GLuint QGLFramebufferObject::handle() const
1281 Q_D(const QGLFramebufferObject);
1285 /*! \fn int QGLFramebufferObject::devType() const
1291 Returns the status of the depth and stencil buffers attached to
1292 this framebuffer object.
1295 QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
1297 Q_D(const QGLFramebufferObject);
1299 return d->fbo_attachment;
1300 return NoAttachment;
1306 Returns true if the framebuffer object is currently bound to a context,
1307 otherwise false is returned.
1310 bool QGLFramebufferObject::isBound() const
1312 Q_D(const QGLFramebufferObject);
1313 const QGLContext *current = QGLContext::currentContext();
1314 return current ? current->d_ptr->current_fbo == d->fbo() : false;
1318 \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1322 Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
1323 is present on this system; otherwise returns false.
1325 \sa blitFramebuffer()
1327 bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1329 return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit);
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.
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.
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.
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.
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.
1357 Note that the scissor test will restrict the blit area if enabled.
1359 This function will have no effect unless hasOpenGLFramebufferBlit() returns
1362 \sa hasOpenGLFramebufferBlit()
1364 void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
1365 QGLFramebufferObject *source, const QRect &sourceRect,
1369 if (!(QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit))
1372 const QGLContext *ctx = QGLContext::currentContext();
1376 const int height = ctx->device()->height();
1378 const int sh = source ? source->height() : height;
1379 const int th = target ? target->height() : height;
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();
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();
1391 glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, source ? source->handle() : 0);
1392 glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, target ? target->handle() : 0);
1394 glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
1398 glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo);