1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtOpenGL module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qglframebufferobject.h"
43 #include "qglframebufferobject_p.h"
46 #include <private/qgl_p.h>
47 #include <private/qfont_p.h>
48 #include "gl2paintengineex/qpaintengineex_opengl2_p.h"
56 extern QImage qt_gl_read_framebuffer(const QSize&, bool, bool);
58 #define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
59 #define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext();
62 #define QT_RESET_GLERROR() \
64 while (glGetError() != GL_NO_ERROR) {} \
66 #define QT_CHECK_GLERROR() \
68 GLenum err = glGetError(); \
69 if (err != GL_NO_ERROR) { \
70 qDebug("[%s line %d] GL Error: %d", \
71 __FILE__, __LINE__, (int)err); \
75 #define QT_RESET_GLERROR() {}
76 #define QT_CHECK_GLERROR() {}
79 // ####TODO Properly #ifdef this class to use #define symbols actually defined
80 // by OpenGL/ES includes
81 #ifndef GL_MAX_SAMPLES
82 #define GL_MAX_SAMPLES 0x8D57
85 #ifndef GL_RENDERBUFFER_SAMPLES
86 #define GL_RENDERBUFFER_SAMPLES 0x8CAB
89 #ifndef GL_DEPTH24_STENCIL8
90 #define GL_DEPTH24_STENCIL8 0x88F0
93 #ifndef GL_DEPTH_COMPONENT24
94 #define GL_DEPTH_COMPONENT24 0x81A6
97 #ifndef GL_READ_FRAMEBUFFER
98 #define GL_READ_FRAMEBUFFER 0x8CA8
101 #ifndef GL_DRAW_FRAMEBUFFER
102 #define GL_DRAW_FRAMEBUFFER 0x8CA9
106 \class QGLFramebufferObjectFormat
108 \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL
116 A framebuffer object has several characteristics:
118 \li \l{setSamples()}{Number of samples per pixels.}
119 \li \l{setAttachment()}{Depth and/or stencil attachments.}
120 \li \l{setTextureTarget()}{Texture target.}
121 \li \l{setInternalTextureFormat()}{Internal texture format.}
124 Note that the desired attachments or number of samples per pixels might not
125 be supported by the hardware driver. Call QGLFramebufferObject::format()
126 after creating a QGLFramebufferObject to find the exact format that was
127 used to create the frame buffer object.
129 \note This class has been deprecated in favor of QOpenGLFramebufferObject.
131 \sa QGLFramebufferObject
137 void QGLFramebufferObjectFormat::detach()
139 if (d->ref.load() != 1) {
140 QGLFramebufferObjectFormatPrivate *newd
141 = new QGLFramebufferObjectFormatPrivate(d);
149 Creates a QGLFramebufferObjectFormat object for specifying
150 the format of an OpenGL framebuffer object.
152 By default the format specifies a non-multisample framebuffer object with no
153 attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8.
154 On OpenGL/ES systems, the default internal format is \c GL_RGBA.
156 \sa samples(), attachment(), internalTextureFormat()
159 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat()
161 d = new QGLFramebufferObjectFormatPrivate;
165 Constructs a copy of \a other.
168 QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other)
175 Assigns \a other to this object.
178 QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other)
190 Destroys the QGLFramebufferObjectFormat.
192 QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat()
199 Sets the number of samples per pixel for a multisample framebuffer object
200 to \a samples. The default sample count of 0 represents a regular
201 non-multisample framebuffer object.
203 If the desired amount of samples per pixel is not supported by the hardware
204 then the maximum number of samples per pixel will be used. Note that
205 multisample framebuffer objects can not be bound as textures. Also, the
206 \c{GL_EXT_framebuffer_multisample} extension is required to create a
207 framebuffer with more than one sample per pixel.
211 void QGLFramebufferObjectFormat::setSamples(int samples)
214 d->samples = samples;
218 Returns the number of samples per pixel if a framebuffer object
219 is a multisample framebuffer object. Otherwise, returns 0.
220 The default value is 0.
224 int QGLFramebufferObjectFormat::samples() const
232 Enables mipmapping if \a enabled is true; otherwise disables it.
234 Mipmapping is disabled by default.
236 If mipmapping is enabled, additional memory will be allocated for
237 the mipmap levels. The mipmap levels can be updated by binding the
238 texture and calling glGenerateMipmap(). Mipmapping cannot be enabled
239 for multisampled framebuffer objects.
241 \sa mipmap(), QGLFramebufferObject::texture()
243 void QGLFramebufferObjectFormat::setMipmap(bool enabled)
252 Returns true if mipmapping is enabled.
256 bool QGLFramebufferObjectFormat::mipmap() const
262 Sets the attachment configuration of a framebuffer object to \a attachment.
266 void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment)
269 d->attachment = attachment;
273 Returns the configuration of the depth and stencil buffers attached to
274 a framebuffer object. The default is QGLFramebufferObject::NoAttachment.
278 QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const
280 return d->attachment;
284 Sets the texture target of the texture attached to a framebuffer object to
285 \a target. Ignored for multisample framebuffer objects.
287 \sa textureTarget(), samples()
289 void QGLFramebufferObjectFormat::setTextureTarget(GLenum target)
296 Returns the texture target of the texture attached to a framebuffer object.
297 Ignored for multisample framebuffer objects. The default is
300 \sa setTextureTarget(), samples()
302 GLenum QGLFramebufferObjectFormat::textureTarget() const
308 Sets the internal format of a framebuffer object's texture or
309 multisample framebuffer object's color buffer to
310 \a internalTextureFormat.
312 \sa internalTextureFormat()
314 void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat)
317 d->internal_format = internalTextureFormat;
321 Returns the internal format of a framebuffer object's texture or
322 multisample framebuffer object's color buffer. The default is
323 \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on
326 \sa setInternalTextureFormat()
328 GLenum QGLFramebufferObjectFormat::internalTextureFormat() const
330 return d->internal_format;
334 Returns true if all the options of this framebuffer object format
335 are the same as \a other; otherwise returns false.
337 bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const
342 return d->equals(other.d);
346 Returns false if all the options of this framebuffer object format
347 are the same as \a other; otherwise returns true.
349 bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const
351 return !(*this == other);
354 void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f,
355 QGLFramebufferObject::Attachment attachment)
358 m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed
360 // The context that the fbo was created in may not have depth
361 // and stencil buffers, but the fbo itself might.
362 fboFormat = QGLContext::currentContext()->format();
363 if (attachment == QGLFramebufferObject::CombinedDepthStencil) {
364 fboFormat.setDepth(true);
365 fboFormat.setStencil(true);
366 } else if (attachment == QGLFramebufferObject::Depth) {
367 fboFormat.setDepth(true);
368 fboFormat.setStencil(false);
370 fboFormat.setDepth(false);
371 fboFormat.setStencil(false);
374 GLenum format = f->format().internalTextureFormat();
375 reqAlpha = (format != GL_RGB
377 && format != GL_RGB5 && format != GL_RGB8
382 QGLContext *QGLFBOGLPaintDevice::context() const
384 return const_cast<QGLContext *>(QGLContext::currentContext());
387 bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const
391 return false; // Context no longer exists.
392 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
395 case GL_FRAMEBUFFER_COMPLETE:
397 case GL_FRAMEBUFFER_UNSUPPORTED:
398 qDebug("QGLFramebufferObject: Unsupported framebuffer format.");
400 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
401 qDebug("QGLFramebufferObject: Framebuffer incomplete attachment.");
403 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
404 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment.");
406 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT
407 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT:
408 qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment.");
411 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
412 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
413 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions.");
416 #ifdef GL_FRAMEBUFFER_INCOMPLETE_FORMATS
417 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS:
418 qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format.");
421 #ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
422 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
423 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer.");
426 #ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
427 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
428 qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer.");
431 #ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
432 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
433 qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel.");
437 qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status;
445 void freeFramebufferFunc(QGLContext *ctx, GLuint id)
448 glDeleteFramebuffers(1, &id);
451 void freeRenderbufferFunc(QGLContext *ctx, GLuint id)
454 glDeleteRenderbuffers(1, &id);
457 void freeTextureFunc(QGLContext *ctx, GLuint id)
460 glDeleteTextures(1, &id);
464 void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz,
465 QGLFramebufferObject::Attachment attachment,
466 GLenum texture_target, GLenum internal_format,
467 GLint samples, bool mipmap)
469 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
471 bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
472 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
476 target = texture_target;
477 // texture dimensions
479 QT_RESET_GLERROR(); // reset error state
481 glGenFramebuffers(1, &fbo);
482 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
485 GLuint color_buffer = 0;
486 GLuint depth_buffer = 0;
487 GLuint stencil_buffer = 0;
492 glGenTextures(1, &texture);
493 glBindTexture(target, texture);
494 glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0,
495 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
497 int width = size.width();
498 int height = size.height();
500 while (width > 1 || height > 1) {
501 width = qMax(1, width >> 1);
502 height = qMax(1, height >> 1);
504 glTexImage2D(target, level, internal_format, width, height, 0,
505 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
508 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
509 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
510 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
511 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
512 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
516 valid = checkFramebufferStatus();
517 glBindTexture(target, 0);
523 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
525 samples = qBound(0, int(samples), int(maxSamples));
527 glGenRenderbuffers(1, &color_buffer);
528 glBindRenderbuffer(GL_RENDERBUFFER, color_buffer);
529 if (glRenderbufferStorageMultisampleEXT && samples > 0) {
530 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
531 internal_format, size.width(), size.height());
534 glRenderbufferStorage(GL_RENDERBUFFER, internal_format,
535 size.width(), size.height());
538 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
539 GL_RENDERBUFFER, color_buffer);
542 valid = checkFramebufferStatus();
545 glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
548 // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
549 // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
550 // might not be supported while separate buffers are, according to QTBUG-12861.
552 if (attachment == QGLFramebufferObject::CombinedDepthStencil
553 && (QGLExtensions::glExtensions() & QGLExtensions::PackedDepthStencil)) {
554 // depth and stencil buffer needs another extension
555 glGenRenderbuffers(1, &depth_buffer);
556 Q_ASSERT(!glIsRenderbuffer(depth_buffer));
557 glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
558 Q_ASSERT(glIsRenderbuffer(depth_buffer));
559 if (samples != 0 && glRenderbufferStorageMultisampleEXT)
560 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
561 GL_DEPTH24_STENCIL8, size.width(), size.height());
563 glRenderbufferStorage(GL_RENDERBUFFER,
564 GL_DEPTH24_STENCIL8, size.width(), size.height());
566 stencil_buffer = depth_buffer;
567 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
568 GL_RENDERBUFFER, depth_buffer);
569 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
570 GL_RENDERBUFFER, stencil_buffer);
572 valid = checkFramebufferStatus();
574 glDeleteRenderbuffers(1, &depth_buffer);
575 stencil_buffer = depth_buffer = 0;
579 if (depth_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil
580 || (attachment == QGLFramebufferObject::Depth)))
582 glGenRenderbuffers(1, &depth_buffer);
583 Q_ASSERT(!glIsRenderbuffer(depth_buffer));
584 glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
585 Q_ASSERT(glIsRenderbuffer(depth_buffer));
586 if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
588 if (QGLExtensions::glExtensions() & QGLExtensions::Depth24) {
589 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
590 GL_DEPTH_COMPONENT24_OES, size.width(), size.height());
592 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
593 GL_DEPTH_COMPONENT16, size.width(), size.height());
596 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
597 GL_DEPTH_COMPONENT, size.width(), size.height());
601 if (QGLExtensions::glExtensions() & QGLExtensions::Depth24) {
602 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES,
603 size.width(), size.height());
605 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
606 size.width(), size.height());
609 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height());
612 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
613 GL_RENDERBUFFER, depth_buffer);
614 valid = checkFramebufferStatus();
616 glDeleteRenderbuffers(1, &depth_buffer);
621 if (stencil_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil)) {
622 glGenRenderbuffers(1, &stencil_buffer);
623 Q_ASSERT(!glIsRenderbuffer(stencil_buffer));
624 glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer);
625 Q_ASSERT(glIsRenderbuffer(stencil_buffer));
626 if (samples != 0 && glRenderbufferStorageMultisampleEXT) {
628 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
629 GL_STENCIL_INDEX8, size.width(), size.height());
631 glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, samples,
632 GL_STENCIL_INDEX, size.width(), size.height());
636 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
637 size.width(), size.height());
639 glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX,
640 size.width(), size.height());
643 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
644 GL_RENDERBUFFER, stencil_buffer);
645 valid = checkFramebufferStatus();
647 glDeleteRenderbuffers(1, &stencil_buffer);
652 // The FBO might have become valid after removing the depth or stencil buffer.
653 valid = checkFramebufferStatus();
655 if (depth_buffer && stencil_buffer) {
656 fbo_attachment = QGLFramebufferObject::CombinedDepthStencil;
657 } else if (depth_buffer) {
658 fbo_attachment = QGLFramebufferObject::Depth;
660 fbo_attachment = QGLFramebufferObject::NoAttachment;
663 glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->current_fbo);
665 fbo_guard = createSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
667 color_buffer_guard = createSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
669 texture_guard = createSharedResourceGuard(ctx, texture, freeTextureFunc);
671 depth_buffer_guard = createSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
672 if (stencil_buffer) {
673 if (stencil_buffer == depth_buffer)
674 stencil_buffer_guard = depth_buffer_guard;
676 stencil_buffer_guard = createSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
680 glDeleteRenderbuffers(1, &color_buffer);
682 glDeleteTextures(1, &texture);
684 glDeleteRenderbuffers(1, &depth_buffer);
685 if (stencil_buffer && depth_buffer != stencil_buffer)
686 glDeleteRenderbuffers(1, &stencil_buffer);
687 glDeleteFramebuffers(1, &fbo);
691 format.setTextureTarget(target);
692 format.setSamples(int(samples));
693 format.setAttachment(fbo_attachment);
694 format.setInternalTextureFormat(internal_format);
695 format.setMipmap(mipmap);
697 glDevice.setFBO(q, attachment);
701 \class QGLFramebufferObject
703 \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object.
708 The QGLFramebufferObject class encapsulates an OpenGL framebuffer
709 object, defined by the \c{GL_EXT_framebuffer_object} extension. In
710 addition it provides a rendering surface that can be painted on
711 with a QPainter, rendered to using native GL calls, or both. This
712 surface can be bound and used as a regular texture in your own GL
713 drawing code. By default, the QGLFramebufferObject class
714 generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target),
715 which is used as the internal rendering target.
717 \b{It is important to have a current GL context when creating a
718 QGLFramebufferObject, otherwise initialization will fail.}
720 OpenGL framebuffer objects and pbuffers (see
721 \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to
722 offscreen surfaces, but there are a number of advantages with
723 using framebuffer objects instead of pbuffers:
726 \li A framebuffer object does not require a separate rendering
727 context, so no context switching will occur when switching
728 rendering targets. There is an overhead involved in switching
729 targets, but in general it is cheaper than a context switch to a
732 \li Rendering to dynamic textures (i.e. render-to-texture
733 functionality) works on all platforms. No need to do explicit copy
734 calls from a render buffer into a texture, as was necessary on
735 systems that did not support the \c{render_texture} extension.
737 \li It is possible to attach several rendering buffers (or texture
738 objects) to the same framebuffer object, and render to all of them
739 without doing a context switch.
741 \li The OpenGL framebuffer extension is a pure GL extension with no
742 system dependant WGL, CGL, or GLX parts. This makes using
743 framebuffer objects more portable.
746 When using a QPainter to paint to a QGLFramebufferObject you should take
747 care that the QGLFramebufferObject is created with the CombinedDepthStencil
748 attachment for QPainter to be able to render correctly.
749 Note that you need to create a QGLFramebufferObject with more than one
750 sample per pixel for primitives to be antialiased when drawing using a
751 QPainter. To create a multisample framebuffer object you should use one of
752 the constructors that take a QGLFramebufferObject parameter, and set the
753 QGLFramebufferObject::samples() property to a non-zero value.
755 When painting to a QGLFramebufferObject using QPainter, the state of
756 the current GL context will be altered by the paint engine to reflect
757 its needs. Applications should not rely upon the GL state being reset
758 to its original conditions, particularly the current shader program,
759 GL viewport, texture units, and drawing modes.
761 For multisample framebuffer objects a color render buffer is created,
762 otherwise a texture with the specified texture target is created.
763 The color render buffer or texture will have the specified internal
764 format, and will be bound to the \c GL_COLOR_ATTACHMENT0
765 attachment in the framebuffer object.
767 If you want to use a framebuffer object with multisampling enabled
768 as a texture, you first need to copy from it to a regular framebuffer
769 object using QGLContext::blitFramebuffer().
773 As of Qt 4.8, it's possible to draw into a QGLFramebufferObject
774 using a QPainter in a separate thread. Note that OpenGL 2.0 or
775 OpenGL ES 2.0 is required for this to work.
777 \sa {Framebuffer Object Example}
782 \enum QGLFramebufferObject::Attachment
785 This enum type is used to configure the depth and stencil buffers
786 attached to the framebuffer object when it is created.
788 \value NoAttachment No attachment is added to the framebuffer object. Note that the
789 OpenGL depth and stencil tests won't work when rendering to a
790 framebuffer object without any depth or stencil buffers.
791 This is the default value.
793 \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present,
794 a combined depth and stencil buffer is attached.
795 If the extension is not present, only a depth buffer is attached.
797 \value Depth A depth buffer is attached to the framebuffer object.
803 /*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
805 Constructs an OpenGL framebuffer object and binds a 2D GL texture
806 to the buffer of the size \a size. The texture is bound to the
807 \c GL_COLOR_ATTACHMENT0 target in the framebuffer object.
809 The \a target parameter is used to specify the GL texture
810 target. The default target is \c GL_TEXTURE_2D. Keep in mind that
811 \c GL_TEXTURE_2D textures must have a power of 2 width and height
812 (e.g. 256x512), unless you are using OpenGL 2.0 or higher.
814 By default, no depth and stencil buffers are attached. This behavior
815 can be toggled using one of the overloaded constructors.
817 The default internal texture format is \c GL_RGBA8 for desktop
818 OpenGL, and \c GL_RGBA for OpenGL/ES.
820 It is important that you have a current GL context set when
821 creating the QGLFramebufferObject, otherwise the initialization
824 \sa size(), texture(), attachment()
827 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target)
828 : d_ptr(new QGLFramebufferObjectPrivate)
830 Q_D(QGLFramebufferObject);
831 d->init(this, size, NoAttachment, target, DEFAULT_FORMAT);
836 Constructs an OpenGL framebuffer object and binds a 2D GL texture
837 to the buffer of the given \a width and \a height.
839 \sa size(), texture()
841 QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target)
842 : d_ptr(new QGLFramebufferObjectPrivate)
844 Q_D(QGLFramebufferObject);
845 d->init(this, QSize(width, height), NoAttachment, target, DEFAULT_FORMAT);
850 Constructs an OpenGL framebuffer object of the given \a size based on the
854 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format)
855 : d_ptr(new QGLFramebufferObjectPrivate)
857 Q_D(QGLFramebufferObject);
858 d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(),
859 format.samples(), format.mipmap());
864 Constructs an OpenGL framebuffer object of the given \a width and \a height
865 based on the supplied \a format.
868 QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format)
869 : d_ptr(new QGLFramebufferObjectPrivate)
871 Q_D(QGLFramebufferObject);
872 d->init(this, QSize(width, height), format.attachment(), format.textureTarget(),
873 format.internalTextureFormat(), format.samples(), format.mipmap());
878 Constructs an OpenGL framebuffer object and binds a texture to the
879 buffer of the given \a width and \a height.
881 The \a attachment parameter describes the depth/stencil buffer
882 configuration, \a target the texture target and \a internal_format
883 the internal texture format. The default texture target is \c
884 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
885 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
887 \sa size(), texture(), attachment()
889 QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment,
890 GLenum target, GLenum internal_format)
891 : d_ptr(new QGLFramebufferObjectPrivate)
893 Q_D(QGLFramebufferObject);
894 d->init(this, QSize(width, height), attachment, target, internal_format);
899 Constructs an OpenGL framebuffer object and binds a texture to the
900 buffer of the given \a size.
902 The \a attachment parameter describes the depth/stencil buffer
903 configuration, \a target the texture target and \a internal_format
904 the internal texture format. The default texture target is \c
905 GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8
906 for desktop OpenGL and \c GL_RGBA for OpenGL/ES.
908 \sa size(), texture(), attachment()
910 QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment,
911 GLenum target, GLenum internal_format)
912 : d_ptr(new QGLFramebufferObjectPrivate)
914 Q_D(QGLFramebufferObject);
915 d->init(this, size, attachment, target, internal_format);
919 \fn QGLFramebufferObject::~QGLFramebufferObject()
921 Destroys the framebuffer object and frees any allocated resources.
923 QGLFramebufferObject::~QGLFramebufferObject()
925 Q_D(QGLFramebufferObject);
929 if (d->texture_guard)
930 d->texture_guard->free();
931 if (d->color_buffer_guard)
932 d->color_buffer_guard->free();
933 if (d->depth_buffer_guard)
934 d->depth_buffer_guard->free();
935 if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard)
936 d->stencil_buffer_guard->free();
938 d->fbo_guard->free();
942 \fn bool QGLFramebufferObject::isValid() const
944 Returns true if the framebuffer object is valid.
946 The framebuffer can become invalid if the initialization process
947 fails, the user attaches an invalid buffer to the framebuffer
948 object, or a non-power of two width/height is specified as the
949 texture size if the texture target is \c{GL_TEXTURE_2D}.
950 The non-power of two limitation does not apply if the OpenGL version
951 is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension
954 The framebuffer can also become invalid if the QGLContext that
955 the framebuffer was created within is destroyed and there are
956 no other shared contexts that can take over ownership of the
959 bool QGLFramebufferObject::isValid() const
961 Q_D(const QGLFramebufferObject);
962 return d->valid && d->fbo_guard && d->fbo_guard->id();
966 \fn bool QGLFramebufferObject::bind()
968 Switches rendering from the default, windowing system provided
969 framebuffer to this framebuffer object.
970 Returns true upon success, false otherwise.
974 bool QGLFramebufferObject::bind()
978 Q_D(QGLFramebufferObject);
981 return false; // Context no longer exists.
982 const QGLContext *current = QGLContext::currentContext();
985 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
987 qWarning("QGLFramebufferObject::bind() called from incompatible context");
990 glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
991 d->valid = d->checkFramebufferStatus();
992 if (d->valid && current)
993 current->d_ptr->current_fbo = d->fbo();
998 \fn bool QGLFramebufferObject::release()
1000 Switches rendering back to the default, windowing system provided
1002 Returns true upon success, false otherwise.
1006 bool QGLFramebufferObject::release()
1012 return false; // Context no longer exists.
1014 const QGLContext *current = QGLContext::currentContext();
1018 QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx))
1020 qWarning("QGLFramebufferObject::release() called from incompatible context");
1025 current->d_ptr->current_fbo = current->d_ptr->default_fbo;
1026 glBindFramebuffer(GL_FRAMEBUFFER, current->d_ptr->default_fbo);
1033 \fn GLuint QGLFramebufferObject::texture() const
1035 Returns the texture id for the texture attached as the default
1036 rendering target in this framebuffer object. This texture id can
1037 be bound as a normal texture in your own GL code.
1039 If a multisample framebuffer object is used then the value returned
1040 from this function will be invalid.
1042 GLuint QGLFramebufferObject::texture() const
1044 Q_D(const QGLFramebufferObject);
1045 return d->texture_guard ? d->texture_guard->id() : 0;
1049 \fn QSize QGLFramebufferObject::size() const
1051 Returns the size of the texture attached to this framebuffer
1054 QSize QGLFramebufferObject::size() const
1056 Q_D(const QGLFramebufferObject);
1061 Returns the format of this framebuffer object.
1063 QGLFramebufferObjectFormat QGLFramebufferObject::format() const
1065 Q_D(const QGLFramebufferObject);
1070 \fn QImage QGLFramebufferObject::toImage() const
1072 Returns the contents of this framebuffer object as a QImage.
1074 QImage QGLFramebufferObject::toImage() const
1076 Q_D(const QGLFramebufferObject);
1080 // qt_gl_read_framebuffer doesn't work on a multisample FBO
1081 if (format().samples() != 0) {
1082 QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat());
1084 QRect rect(QPoint(0, 0), size());
1085 blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect);
1087 return temp.toImage();
1090 bool wasBound = isBound();
1092 const_cast<QGLFramebufferObject *>(this)->bind();
1093 QImage image = qt_gl_read_framebuffer(d->size, format().internalTextureFormat() != GL_RGB, true);
1095 const_cast<QGLFramebufferObject *>(this)->release();
1100 Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine)
1103 QPaintEngine *QGLFramebufferObject::paintEngine() const
1105 Q_D(const QGLFramebufferObject);
1109 QPaintEngine *engine = qt_buffer_2_engine()->engine();
1110 if (engine->isActive() && engine->paintDevice() != this) {
1111 d->engine = new QGL2PaintEngineEx;
1118 \fn bool QGLFramebufferObject::bindDefault()
1121 Switches rendering back to the default, windowing system provided
1123 Returns true upon success, false otherwise.
1125 \sa bind(), release()
1127 bool QGLFramebufferObject::bindDefault()
1129 QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext());
1132 bool ext_detected = (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
1133 if (!ext_detected || (ext_detected && !qt_resolve_framebufferobject_extensions(ctx)))
1136 ctx->d_ptr->current_fbo = ctx->d_ptr->default_fbo;
1137 glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->default_fbo);
1140 qWarning("QGLFramebufferObject::bindDefault() called without current context.");
1148 \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1150 Returns true if the OpenGL \c{GL_EXT_framebuffer_object} extension
1151 is present on this system; otherwise returns false.
1153 bool QGLFramebufferObject::hasOpenGLFramebufferObjects()
1155 return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferObject);
1161 Draws the given texture, \a textureId, to the given target rectangle,
1162 \a target, in OpenGL model space. The \a textureTarget should be a 2D
1165 The framebuffer object should be bound when calling this function.
1167 Equivalent to the corresponding QGLContext::drawTexture().
1169 void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget)
1171 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget);
1177 Draws the given texture, \a textureId, at the given \a point in OpenGL
1178 model space. The \a textureTarget should be a 2D texture target.
1180 The framebuffer object should be bound when calling this function.
1182 Equivalent to the corresponding QGLContext::drawTexture().
1184 void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget)
1186 const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget);
1190 int QGLFramebufferObject::metric(PaintDeviceMetric metric) const
1192 Q_D(const QGLFramebufferObject);
1194 float dpmx = qt_defaultDpiX()*100./2.54;
1195 float dpmy = qt_defaultDpiY()*100./2.54;
1196 int w = d->size.width();
1197 int h = d->size.height();
1206 return qRound(w * 1000 / dpmx);
1209 return qRound(h * 1000 / dpmy);
1215 return 32;//d->depth;
1218 return qRound(dpmx * 0.0254);
1221 return qRound(dpmy * 0.0254);
1223 case PdmPhysicalDpiX:
1224 return qRound(dpmx * 0.0254);
1226 case PdmPhysicalDpiY:
1227 return qRound(dpmy * 0.0254);
1230 qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric);
1237 \fn GLuint QGLFramebufferObject::handle() const
1239 Returns the GL framebuffer object handle for this framebuffer
1240 object (returned by the \c{glGenFrameBuffersEXT()} function). This
1241 handle can be used to attach new images or buffers to the
1242 framebuffer. The user is responsible for cleaning up and
1243 destroying these objects.
1245 GLuint QGLFramebufferObject::handle() const
1247 Q_D(const QGLFramebufferObject);
1251 /*! \fn int QGLFramebufferObject::devType() const
1257 Returns the status of the depth and stencil buffers attached to
1258 this framebuffer object.
1261 QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const
1263 Q_D(const QGLFramebufferObject);
1265 return d->fbo_attachment;
1266 return NoAttachment;
1272 Returns true if the framebuffer object is currently bound to a context,
1273 otherwise false is returned.
1276 bool QGLFramebufferObject::isBound() const
1278 Q_D(const QGLFramebufferObject);
1279 const QGLContext *current = QGLContext::currentContext();
1280 return current ? current->d_ptr->current_fbo == d->fbo() : false;
1284 \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1288 Returns true if the OpenGL \c{GL_EXT_framebuffer_blit} extension
1289 is present on this system; otherwise returns false.
1291 \sa blitFramebuffer()
1293 bool QGLFramebufferObject::hasOpenGLFramebufferBlit()
1295 return (QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit);
1301 Blits from the \a sourceRect rectangle in the \a source framebuffer
1302 object to the \a targetRect rectangle in the \a target framebuffer object.
1304 If \a source or \a target is 0, the default framebuffer will be used
1305 instead of a framebuffer object as source or target respectively.
1307 The \a buffers parameter should be a mask consisting of any combination of
1308 \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and
1309 \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both
1310 in the source and target buffers is ignored.
1312 The \a sourceRect and \a targetRect rectangles may have different sizes;
1313 in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or
1314 \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to
1315 \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest
1316 interpolation should be used when scaling is performed.
1318 If \a source equals \a target a copy is performed within the same buffer.
1319 Results are undefined if the source and target rectangles overlap and
1320 have different sizes. The sizes must also be the same if any of the
1321 framebuffer objects are multisample framebuffers.
1323 Note that the scissor test will restrict the blit area if enabled.
1325 This function will have no effect unless hasOpenGLFramebufferBlit() returns
1328 \sa hasOpenGLFramebufferBlit()
1330 void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect,
1331 QGLFramebufferObject *source, const QRect &sourceRect,
1335 if (!(QGLExtensions::glExtensions() & QGLExtensions::FramebufferBlit))
1338 const QGLContext *ctx = QGLContext::currentContext();
1339 if (!ctx || !ctx->contextHandle())
1342 QSurface *surface = ctx->contextHandle()->surface();
1344 const int height = static_cast<QWindow *>(surface)->height();
1346 const int sh = source ? source->height() : height;
1347 const int th = target ? target->height() : height;
1349 const int sx0 = sourceRect.left();
1350 const int sx1 = sourceRect.left() + sourceRect.width();
1351 const int sy0 = sh - (sourceRect.top() + sourceRect.height());
1352 const int sy1 = sh - sourceRect.top();
1354 const int tx0 = targetRect.left();
1355 const int tx1 = targetRect.left() + targetRect.width();
1356 const int ty0 = th - (targetRect.top() + targetRect.height());
1357 const int ty1 = th - targetRect.top();
1359 glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0);
1360 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0);
1362 glBlitFramebufferEXT(sx0, sy0, sx1, sy1,
1366 glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->current_fbo);