diff options
Diffstat (limited to 'src/opengl/qglframebufferobject.cpp')
-rw-r--r-- | src/opengl/qglframebufferobject.cpp | 1466 |
1 files changed, 0 insertions, 1466 deletions
diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp deleted file mode 100644 index d0f82a85fa..0000000000 --- a/src/opengl/qglframebufferobject.cpp +++ /dev/null @@ -1,1466 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglframebufferobject.h" -#include "qglframebufferobject_p.h" - -#include <qdebug.h> -#include <private/qgl_p.h> -#include <private/qfont_p.h> -#include "gl2paintengineex/qpaintengineex_opengl2_p.h" - -#include <qimage.h> -#include <qwindow.h> - -QT_BEGIN_NAMESPACE - -extern QImage qt_gl_read_frame_buffer(const QSize&, bool, bool); - -#define QGL_FUNC_CONTEXT const QGLContext *ctx = QGLContext::currentContext(); -#define QGL_FUNCP_CONTEXT const QGLContext *ctx = QGLContext::currentContext(); - -#ifndef QT_NO_DEBUG -#define QT_RESET_GLERROR() \ -{ \ - while (QOpenGLContext::currentContext()->functions()->glGetError() != GL_NO_ERROR) {} \ -} -#define QT_CHECK_GLERROR() \ -{ \ - GLenum err = QOpenGLContext::currentContext()->functions()->glGetError(); \ - if (err != GL_NO_ERROR) { \ - qDebug("[%s line %d] GL Error: %d", \ - __FILE__, __LINE__, (int)err); \ - } \ -} -#else -#define QT_RESET_GLERROR() {} -#define QT_CHECK_GLERROR() {} -#endif - -// ####TODO Properly #ifdef this class to use #define symbols actually defined -// by OpenGL/ES includes -#ifndef GL_MAX_SAMPLES -#define GL_MAX_SAMPLES 0x8D57 -#endif - -#ifndef GL_RENDERBUFFER_SAMPLES -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#endif - -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif - -#ifndef GL_DEPTH_COMPONENT24 -#define GL_DEPTH_COMPONENT24 0x81A6 -#endif - -#ifndef GL_DEPTH_COMPONENT24_OES -#define GL_DEPTH_COMPONENT24_OES 0x81A6 -#endif - -#ifndef GL_READ_FRAMEBUFFER -#define GL_READ_FRAMEBUFFER 0x8CA8 -#endif - -#ifndef GL_DRAW_FRAMEBUFFER -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#endif - -#ifndef GL_DEPTH_STENCIL_ATTACHMENT -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#endif - -#ifndef GL_DEPTH_STENCIL -#define GL_DEPTH_STENCIL 0x84F9 -#endif - -/*! - \class QGLFramebufferObjectFormat - \inmodule QtOpenGL - \brief The QGLFramebufferObjectFormat class specifies the format of an OpenGL - framebuffer object. - - \since 4.6 - \obsolete - - \ingroup painting-3D - - A framebuffer object has several characteristics: - \list - \li \l{setSamples()}{Number of samples per pixels.} - \li \l{setAttachment()}{Depth and/or stencil attachments.} - \li \l{setTextureTarget()}{Texture target.} - \li \l{setInternalTextureFormat()}{Internal texture format.} - \endlist - - Note that the desired attachments or number of samples per pixels might not - be supported by the hardware driver. Call QGLFramebufferObject::format() - after creating a QGLFramebufferObject to find the exact format that was - used to create the frame buffer object. - - \note This class has been deprecated in favor of QOpenGLFramebufferObjectFormat. - - \sa QGLFramebufferObject -*/ - -/*! - \internal -*/ -void QGLFramebufferObjectFormat::detach() -{ - if (d->ref.loadRelaxed() != 1) { - QGLFramebufferObjectFormatPrivate *newd - = new QGLFramebufferObjectFormatPrivate(d); - if (!d->ref.deref()) - delete d; - d = newd; - } -} - -/*! - Creates a QGLFramebufferObjectFormat object for specifying - the format of an OpenGL framebuffer object. - - By default the format specifies a non-multisample framebuffer object with no - attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8. - On OpenGL/ES systems, the default internal format is \c GL_RGBA. - - \sa samples(), attachment(), internalTextureFormat() -*/ - -QGLFramebufferObjectFormat::QGLFramebufferObjectFormat() -{ - d = new QGLFramebufferObjectFormatPrivate; -} - -/*! - Constructs a copy of \a other. -*/ - -QGLFramebufferObjectFormat::QGLFramebufferObjectFormat(const QGLFramebufferObjectFormat &other) -{ - d = other.d; - d->ref.ref(); -} - -/*! - Assigns \a other to this object. -*/ - -QGLFramebufferObjectFormat &QGLFramebufferObjectFormat::operator=(const QGLFramebufferObjectFormat &other) -{ - if (d != other.d) { - other.d->ref.ref(); - if (!d->ref.deref()) - delete d; - d = other.d; - } - return *this; -} - -/*! - Destroys the QGLFramebufferObjectFormat. -*/ -QGLFramebufferObjectFormat::~QGLFramebufferObjectFormat() -{ - if (!d->ref.deref()) - delete d; -} - -/*! - Sets the number of samples per pixel for a multisample framebuffer object - to \a samples. The default sample count of 0 represents a regular - non-multisample framebuffer object. - - If the desired amount of samples per pixel is not supported by the hardware - then the maximum number of samples per pixel will be used. Note that - multisample framebuffer objects cannot be bound as textures. Also, the - \c{GL_EXT_framebuffer_multisample} extension is required to create a - framebuffer with more than one sample per pixel. - - \sa samples() -*/ -void QGLFramebufferObjectFormat::setSamples(int samples) -{ - detach(); - d->samples = samples; -} - -/*! - Returns the number of samples per pixel if a framebuffer object - is a multisample framebuffer object. Otherwise, returns 0. - The default value is 0. - - \sa setSamples() -*/ -int QGLFramebufferObjectFormat::samples() const -{ - return d->samples; -} - -/*! - \since 4.8 - - Enables mipmapping if \a enabled is true; otherwise disables it. - - Mipmapping is disabled by default. - - If mipmapping is enabled, additional memory will be allocated for - the mipmap levels. The mipmap levels can be updated by binding the - texture and calling glGenerateMipmap(). Mipmapping cannot be enabled - for multisampled framebuffer objects. - - \sa mipmap(), QGLFramebufferObject::texture() -*/ -void QGLFramebufferObjectFormat::setMipmap(bool enabled) -{ - detach(); - d->mipmap = enabled; -} - -/*! - \since 4.8 - - Returns \c true if mipmapping is enabled. - - \sa setMipmap() -*/ -bool QGLFramebufferObjectFormat::mipmap() const -{ - return d->mipmap; -} - -/*! - Sets the attachment configuration of a framebuffer object to \a attachment. - - \sa attachment() -*/ -void QGLFramebufferObjectFormat::setAttachment(QGLFramebufferObject::Attachment attachment) -{ - detach(); - d->attachment = attachment; -} - -/*! - Returns the configuration of the depth and stencil buffers attached to - a framebuffer object. The default is QGLFramebufferObject::NoAttachment. - - \sa setAttachment() -*/ -QGLFramebufferObject::Attachment QGLFramebufferObjectFormat::attachment() const -{ - return d->attachment; -} - -/*! - Sets the texture target of the texture attached to a framebuffer object to - \a target. Ignored for multisample framebuffer objects. - - \sa textureTarget(), samples() -*/ -void QGLFramebufferObjectFormat::setTextureTarget(GLenum target) -{ - detach(); - d->target = target; -} - -/*! - Returns the texture target of the texture attached to a framebuffer object. - Ignored for multisample framebuffer objects. The default is - \c GL_TEXTURE_2D. - - \sa setTextureTarget(), samples() -*/ -GLenum QGLFramebufferObjectFormat::textureTarget() const -{ - return d->target; -} - -/*! - Sets the internal format of a framebuffer object's texture or - multisample framebuffer object's color buffer to - \a internalTextureFormat. - - \sa internalTextureFormat() -*/ -void QGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat) -{ - detach(); - d->internal_format = internalTextureFormat; -} - -/*! - Returns the internal format of a framebuffer object's texture or - multisample framebuffer object's color buffer. The default is - \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on - OpenGL/ES systems. - - \sa setInternalTextureFormat() -*/ -GLenum QGLFramebufferObjectFormat::internalTextureFormat() const -{ - return d->internal_format; -} - -/*! - Returns \c true if all the options of this framebuffer object format - are the same as \a other; otherwise returns \c false. -*/ -bool QGLFramebufferObjectFormat::operator==(const QGLFramebufferObjectFormat& other) const -{ - if (d == other.d) - return true; - else - return d->equals(other.d); -} - -/*! - Returns \c false if all the options of this framebuffer object format - are the same as \a other; otherwise returns \c true. -*/ -bool QGLFramebufferObjectFormat::operator!=(const QGLFramebufferObjectFormat& other) const -{ - return !(*this == other); -} - -void QGLFBOGLPaintDevice::setFBO(QGLFramebufferObject* f, - QGLFramebufferObject::Attachment attachment) -{ - fbo = f; - m_thisFBO = fbo->d_func()->fbo(); // This shouldn't be needed - - // The context that the fbo was created in may not have depth - // and stencil buffers, but the fbo itself might. - fboFormat = QGLContext::currentContext()->format(); - if (attachment == QGLFramebufferObject::CombinedDepthStencil) { - fboFormat.setDepth(true); - fboFormat.setStencil(true); - } else if (attachment == QGLFramebufferObject::Depth) { - fboFormat.setDepth(true); - fboFormat.setStencil(false); - } else { - fboFormat.setDepth(false); - fboFormat.setStencil(false); - } - - GLenum format = f->format().internalTextureFormat(); - reqAlpha = (format != GL_RGB -#ifdef GL_RGB5 - && format != GL_RGB5 -#endif -#ifdef GL_RGB8 - && format != GL_RGB8 -#endif - ); -} - -QGLContext *QGLFBOGLPaintDevice::context() const -{ - return const_cast<QGLContext *>(QGLContext::currentContext()); -} - -bool QGLFramebufferObjectPrivate::checkFramebufferStatus() const -{ - QGL_FUNCP_CONTEXT; - if (!ctx) - return false; // Context no longer exists. - GLenum status = ctx->contextHandle()->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER); - switch(status) { - case GL_NO_ERROR: - case GL_FRAMEBUFFER_COMPLETE: - return true; - case GL_FRAMEBUFFER_UNSUPPORTED: - qDebug("QGLFramebufferObject: Unsupported framebuffer format."); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - qDebug("QGLFramebufferObject: Framebuffer incomplete attachment."); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - qDebug("QGLFramebufferObject: Framebuffer incomplete, missing attachment."); - break; -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT - case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT: - qDebug("QGLFramebufferObject: Framebuffer incomplete, duplicate attachment."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_FORMATS - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: - qDebug("QGLFramebufferObject: Framebuffer incomplete, attached images must have same format."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - qDebug("QGLFramebufferObject: Framebuffer incomplete, missing draw buffer."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - qDebug("QGLFramebufferObject: Framebuffer incomplete, missing read buffer."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - qDebug("QGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel."); - break; -#endif - default: - qDebug() <<"QGLFramebufferObject: An undefined error has occurred: "<< status; - break; - } - return false; -} - -namespace -{ - void freeFramebufferFunc(QGLContext *ctx, GLuint id) - { - Q_ASSERT(ctx); - ctx->contextHandle()->functions()->glDeleteFramebuffers(1, &id); - } - - void freeRenderbufferFunc(QGLContext *ctx, GLuint id) - { - Q_ASSERT(ctx); - ctx->contextHandle()->functions()->glDeleteRenderbuffers(1, &id); - } - - void freeTextureFunc(QGLContext *ctx, GLuint id) - { - Q_UNUSED(ctx); - ctx->contextHandle()->functions()->glDeleteTextures(1, &id); - } -} - -void QGLFramebufferObjectPrivate::init(QGLFramebufferObject *q, const QSize &sz, - QGLFramebufferObject::Attachment attachment, - GLenum texture_target, GLenum internal_format, - GLint samples, bool mipmap) -{ - QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - - funcs.initializeOpenGLFunctions(); - - if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) - return; - - ctx->d_ptr->refreshCurrentFbo(); - - size = sz; - target = texture_target; - // texture dimensions - - QT_RESET_GLERROR(); // reset error state - GLuint fbo = 0; - funcs.glGenFramebuffers(1, &fbo); - funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - GLuint texture = 0; - GLuint color_buffer = 0; - GLuint depth_buffer = 0; - GLuint stencil_buffer = 0; - - QT_CHECK_GLERROR(); - // init texture - if (samples == 0) { - funcs.glGenTextures(1, &texture); - funcs.glBindTexture(target, texture); - funcs.glTexImage2D(target, 0, internal_format, size.width(), size.height(), 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - if (mipmap) { - int width = size.width(); - int height = size.height(); - int level = 0; - while (width > 1 || height > 1) { - width = qMax(1, width >> 1); - height = qMax(1, height >> 1); - ++level; - funcs.glTexImage2D(target, level, internal_format, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } - } - funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - target, texture, 0); - - QT_CHECK_GLERROR(); - valid = checkFramebufferStatus(); - funcs.glBindTexture(target, 0); - - color_buffer = 0; - } else { - mipmap = false; - GLint maxSamples; - funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); - - samples = qBound(0, int(samples), int(maxSamples)); - - funcs.glGenRenderbuffers(1, &color_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, color_buffer); - if (funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) && samples > 0) { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - internal_format, size.width(), size.height()); - } else { - samples = 0; - funcs.glRenderbufferStorage(GL_RENDERBUFFER, internal_format, - size.width(), size.height()); - } - - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, color_buffer); - - QT_CHECK_GLERROR(); - valid = checkFramebufferStatus(); - - if (valid) - funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples); - } - - // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a - // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer - // might not be supported while separate buffers are, according to QTBUG-12861. - - if (attachment == QGLFramebufferObject::CombinedDepthStencil - && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil)) { - // depth and stencil buffer needs another extension - funcs.glGenRenderbuffers(1, &depth_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); -#ifndef Q_OS_WASM - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH24_STENCIL8, size.width(), size.height()); - else - funcs.glRenderbufferStorage(GL_RENDERBUFFER, - GL_DEPTH24_STENCIL8, size.width(), size.height()); - - stencil_buffer = depth_buffer; - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depth_buffer); - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil_buffer); -#else - // webgl does not allow separate depth and stencil attachments - if (samples != 0) { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_STENCIL, size.width(), size.height()); - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, - size.width(), size.height()); - } - stencil_buffer = depth_buffer; - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, depth_buffer); -#endif - - valid = checkFramebufferStatus(); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &depth_buffer); - stencil_buffer = depth_buffer = 0; - } - } - - if (depth_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil - || (attachment == QGLFramebufferObject::Depth))) - { - funcs.glGenRenderbuffers(1, &depth_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { -#ifdef QT_OPENGL_ES - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT24_OES, size.width(), size.height()); - } else { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT16, size.width(), size.height()); - } -#else - if (ctx->contextHandle()->isOpenGLES()) { - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT24, size.width(), size.height()); - else - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT16, size.width(), size.height()); - } else { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT, size.width(), size.height()); - } -#endif - } else { -#ifdef QT_OPENGL_ES - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, - size.width(), size.height()); - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - size.width(), size.height()); - } -#else - if (ctx->contextHandle()->isOpenGLES()) { - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, - size.width(), size.height()); - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - size.width(), size.height()); - } - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.width(), size.height()); - } -#endif - } - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depth_buffer); - valid = checkFramebufferStatus(); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &depth_buffer); - depth_buffer = 0; - } - } - - if (stencil_buffer == 0 && (attachment == QGLFramebufferObject::CombinedDepthStencil)) { - funcs.glGenRenderbuffers(1, &stencil_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer)); - -#ifdef QT_OPENGL_ES - GLenum storage = GL_STENCIL_INDEX8; -#else - GLenum storage = ctx->contextHandle()->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; -#endif - - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, size.width(), size.height()); - else - funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, size.width(), size.height()); - - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil_buffer); - valid = checkFramebufferStatus(); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &stencil_buffer); - stencil_buffer = 0; - } - } - - // The FBO might have become valid after removing the depth or stencil buffer. - valid = checkFramebufferStatus(); - - if (depth_buffer && stencil_buffer) { - fbo_attachment = QGLFramebufferObject::CombinedDepthStencil; - } else if (depth_buffer) { - fbo_attachment = QGLFramebufferObject::Depth; - } else { - fbo_attachment = QGLFramebufferObject::NoAttachment; - } - - funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->current_fbo); - if (valid) { - fbo_guard = createSharedResourceGuard(ctx, fbo, freeFramebufferFunc); - if (color_buffer) - color_buffer_guard = createSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc); - else - texture_guard = createSharedResourceGuard(ctx, texture, freeTextureFunc); - if (depth_buffer) - depth_buffer_guard = createSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc); - if (stencil_buffer) { - if (stencil_buffer == depth_buffer) - stencil_buffer_guard = depth_buffer_guard; - else - stencil_buffer_guard = createSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc); - } - } else { - if (color_buffer) - funcs.glDeleteRenderbuffers(1, &color_buffer); - else - funcs.glDeleteTextures(1, &texture); - if (depth_buffer) - funcs.glDeleteRenderbuffers(1, &depth_buffer); - if (stencil_buffer && depth_buffer != stencil_buffer) - funcs.glDeleteRenderbuffers(1, &stencil_buffer); - funcs.glDeleteFramebuffers(1, &fbo); - } - QT_CHECK_GLERROR(); - - format.setTextureTarget(target); - format.setSamples(int(samples)); - format.setAttachment(fbo_attachment); - format.setInternalTextureFormat(internal_format); - format.setMipmap(mipmap); - - glDevice.setFBO(q, attachment); -} - -/*! - \class QGLFramebufferObject - \inmodule QtOpenGL - \brief The QGLFramebufferObject class encapsulates an OpenGL framebuffer object. - \since 4.2 - - \obsolete - - \ingroup painting-3D - - The QGLFramebufferObject class encapsulates an OpenGL framebuffer - object, defined by the \c{GL_EXT_framebuffer_object} extension. In - addition it provides a rendering surface that can be painted on - with a QPainter, rendered to using native GL calls, or both. This - surface can be bound and used as a regular texture in your own GL - drawing code. By default, the QGLFramebufferObject class - generates a 2D GL texture (using the \c{GL_TEXTURE_2D} target), - which is used as the internal rendering target. - - \b{It is important to have a current GL context when creating a - QGLFramebufferObject, otherwise initialization will fail.} - - OpenGL framebuffer objects and pbuffers (see - \l{QGLPixelBuffer}{QGLPixelBuffer}) can both be used to render to - offscreen surfaces, but there are a number of advantages with - using framebuffer objects instead of pbuffers: - - \list 1 - \li A framebuffer object does not require a separate rendering - context, so no context switching will occur when switching - rendering targets. There is an overhead involved in switching - targets, but in general it is cheaper than a context switch to a - pbuffer. - - \li Rendering to dynamic textures (i.e. render-to-texture - functionality) works on all platforms. No need to do explicit copy - calls from a render buffer into a texture, as was necessary on - systems that did not support the \c{render_texture} extension. - - \li It is possible to attach several rendering buffers (or texture - objects) to the same framebuffer object, and render to all of them - without doing a context switch. - - \li The OpenGL framebuffer extension is a pure GL extension with no - system dependant WGL, CGL, or GLX parts. This makes using - framebuffer objects more portable. - \endlist - - When using a QPainter to paint to a QGLFramebufferObject you should take - care that the QGLFramebufferObject is created with the CombinedDepthStencil - attachment for QPainter to be able to render correctly. - Note that you need to create a QGLFramebufferObject with more than one - sample per pixel for primitives to be antialiased when drawing using a - QPainter. To create a multisample framebuffer object you should use one of - the constructors that take a QGLFramebufferObjectFormat parameter, and set - the QGLFramebufferObjectFormat::samples() property to a non-zero value. - - When painting to a QGLFramebufferObject using QPainter, the state of - the current GL context will be altered by the paint engine to reflect - its needs. Applications should not rely upon the GL state being reset - to its original conditions, particularly the current shader program, - GL viewport, texture units, and drawing modes. - - For multisample framebuffer objects a color render buffer is created, - otherwise a texture with the specified texture target is created. - The color render buffer or texture will have the specified internal - format, and will be bound to the \c GL_COLOR_ATTACHMENT0 - attachment in the framebuffer object. - - If you want to use a framebuffer object with multisampling enabled - as a texture, you first need to copy from it to a regular framebuffer - object using QGLContext::blitFramebuffer(). - - \section1 Threading - - As of Qt 4.8, it's possible to draw into a QGLFramebufferObject - using a QPainter in a separate thread. Note that OpenGL 2.0 or - OpenGL ES 2.0 is required for this to work. - - \note This class has been deprecated in favor of QOpenGLFramebufferObject. -*/ - - -/*! - \enum QGLFramebufferObject::Attachment - \since 4.3 - - This enum type is used to configure the depth and stencil buffers - attached to the framebuffer object when it is created. - - \value NoAttachment No attachment is added to the framebuffer object. Note that the - OpenGL depth and stencil tests won't work when rendering to a - framebuffer object without any depth or stencil buffers. - This is the default value. - - \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present, - a combined depth and stencil buffer is attached. - If the extension is not present, only a depth buffer is attached. - - \value Depth A depth buffer is attached to the framebuffer object. - - \sa attachment() -*/ - - -/*! \fn QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target) - - Constructs an OpenGL framebuffer object and binds a 2D GL texture - to the buffer of the size \a size. The texture is bound to the - \c GL_COLOR_ATTACHMENT0 target in the framebuffer object. - - The \a target parameter is used to specify the GL texture - target. The default target is \c GL_TEXTURE_2D. Keep in mind that - \c GL_TEXTURE_2D textures must have a power of 2 width and height - (e.g. 256x512), unless you are using OpenGL 2.0 or higher. - - By default, no depth and stencil buffers are attached. This behavior - can be toggled using one of the overloaded constructors. - - The default internal texture format is \c GL_RGBA8 for desktop - OpenGL, and \c GL_RGBA for OpenGL/ES. - - It is important that you have a current GL context set when - creating the QGLFramebufferObject, otherwise the initialization - will fail. - - \sa size(), texture(), attachment() -*/ - -QGLFramebufferObject::QGLFramebufferObject(const QSize &size, GLenum target) - : d_ptr(new QGLFramebufferObjectPrivate) -{ - Q_D(QGLFramebufferObject); - d->init(this, size, NoAttachment, target, -#ifndef QT_OPENGL_ES_2 - QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8 -#else - GL_RGBA -#endif - ); -} - -/*! \overload - - Constructs an OpenGL framebuffer object and binds a 2D GL texture - to the buffer of the given \a width and \a height. - - \sa size(), texture() -*/ -QGLFramebufferObject::QGLFramebufferObject(int width, int height, GLenum target) - : d_ptr(new QGLFramebufferObjectPrivate) -{ - Q_D(QGLFramebufferObject); - d->init(this, QSize(width, height), NoAttachment, target, -#ifndef QT_OPENGL_ES_2 - QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8 -#else - GL_RGBA -#endif - ); -} - -/*! \overload - - Constructs an OpenGL framebuffer object of the given \a size based on the - supplied \a format. -*/ - -QGLFramebufferObject::QGLFramebufferObject(const QSize &size, const QGLFramebufferObjectFormat &format) - : d_ptr(new QGLFramebufferObjectPrivate) -{ - Q_D(QGLFramebufferObject); - d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), - format.samples(), format.mipmap()); -} - -/*! \overload - - Constructs an OpenGL framebuffer object of the given \a width and \a height - based on the supplied \a format. -*/ - -QGLFramebufferObject::QGLFramebufferObject(int width, int height, const QGLFramebufferObjectFormat &format) - : d_ptr(new QGLFramebufferObjectPrivate) -{ - Q_D(QGLFramebufferObject); - d->init(this, QSize(width, height), format.attachment(), format.textureTarget(), - format.internalTextureFormat(), format.samples(), format.mipmap()); -} - -/*! \overload - - Constructs an OpenGL framebuffer object and binds a texture to the - buffer of the given \a width and \a height. - - The \a attachment parameter describes the depth/stencil buffer - configuration, \a target the texture target and \a internal_format - the internal texture format. The default texture target is \c - GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 - for desktop OpenGL and \c GL_RGBA for OpenGL/ES. - - \sa size(), texture(), attachment() -*/ -QGLFramebufferObject::QGLFramebufferObject(int width, int height, Attachment attachment, - GLenum target, GLenum internal_format) - : d_ptr(new QGLFramebufferObjectPrivate) -{ - Q_D(QGLFramebufferObject); - if (!internal_format) -#ifdef QT_OPENGL_ES_2 - internal_format = GL_RGBA; -#else - internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; -#endif - d->init(this, QSize(width, height), attachment, target, internal_format); -} - -/*! \overload - - Constructs an OpenGL framebuffer object and binds a texture to the - buffer of the given \a size. - - The \a attachment parameter describes the depth/stencil buffer - configuration, \a target the texture target and \a internal_format - the internal texture format. The default texture target is \c - GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 - for desktop OpenGL and \c GL_RGBA for OpenGL/ES. - - \sa size(), texture(), attachment() -*/ -QGLFramebufferObject::QGLFramebufferObject(const QSize &size, Attachment attachment, - GLenum target, GLenum internal_format) - : d_ptr(new QGLFramebufferObjectPrivate) -{ - Q_D(QGLFramebufferObject); - if (!internal_format) -#ifdef QT_OPENGL_ES_2 - internal_format = GL_RGBA; -#else - internal_format = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; -#endif - d->init(this, size, attachment, target, internal_format); -} - -/*! - \fn QGLFramebufferObject::~QGLFramebufferObject() - - Destroys the framebuffer object and frees any allocated resources. -*/ -QGLFramebufferObject::~QGLFramebufferObject() -{ - Q_D(QGLFramebufferObject); - - delete d->engine; - - if (d->texture_guard) - d->texture_guard->free(); - if (d->color_buffer_guard) - d->color_buffer_guard->free(); - if (d->depth_buffer_guard) - d->depth_buffer_guard->free(); - if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard) - d->stencil_buffer_guard->free(); - if (d->fbo_guard) - d->fbo_guard->free(); -} - -/*! - \fn bool QGLFramebufferObject::isValid() const - - Returns \c true if the framebuffer object is valid. - - The framebuffer can become invalid if the initialization process - fails, the user attaches an invalid buffer to the framebuffer - object, or a non-power of two width/height is specified as the - texture size if the texture target is \c{GL_TEXTURE_2D}. - The non-power of two limitation does not apply if the OpenGL version - is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension - is present. - - The framebuffer can also become invalid if the QGLContext that - the framebuffer was created within is destroyed and there are - no other shared contexts that can take over ownership of the - framebuffer. -*/ -bool QGLFramebufferObject::isValid() const -{ - Q_D(const QGLFramebufferObject); - return d->valid && d->fbo_guard && d->fbo_guard->id(); -} - -/*! - \fn bool QGLFramebufferObject::bind() - - Switches rendering from the default, windowing system provided - framebuffer to this framebuffer object. - Returns \c true upon success, false otherwise. - - \sa release() -*/ -bool QGLFramebufferObject::bind() -{ - if (!isValid()) - return false; - Q_D(QGLFramebufferObject); - QGL_FUNC_CONTEXT; - if (!ctx) - return false; // Context no longer exists. - const QGLContext *current = QGLContext::currentContext(); -#ifdef QT_DEBUG - if (!current || - QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx)) - { - qWarning("QGLFramebufferObject::bind() called from incompatible context"); - } -#endif - d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); - d->valid = d->checkFramebufferStatus(); - if (d->valid && current) - current->d_ptr->setCurrentFbo(d->fbo()); - return d->valid; -} - -/*! - \fn bool QGLFramebufferObject::release() - - Switches rendering back to the default, windowing system provided - framebuffer. - Returns \c true upon success, false otherwise. - - \sa bind() -*/ -bool QGLFramebufferObject::release() -{ - if (!isValid()) - return false; - Q_D(QGLFramebufferObject); - QGL_FUNC_CONTEXT; - if (!ctx) - return false; // Context no longer exists. - - const QGLContext *current = QGLContext::currentContext(); - -#ifdef QT_DEBUG - if (!current || - QGLContextPrivate::contextGroup(current) != QGLContextPrivate::contextGroup(ctx)) - { - qWarning("QGLFramebufferObject::release() called from incompatible context"); - } -#endif - - if (current) { - current->d_ptr->setCurrentFbo(current->d_ptr->default_fbo); - d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_ptr->default_fbo); - } - - return true; -} - -/*! - \fn GLuint QGLFramebufferObject::texture() const - - Returns the texture id for the texture attached as the default - rendering target in this framebuffer object. This texture id can - be bound as a normal texture in your own GL code. - - If a multisample framebuffer object is used then the value returned - from this function will be invalid. -*/ -GLuint QGLFramebufferObject::texture() const -{ - Q_D(const QGLFramebufferObject); - return d->texture_guard ? d->texture_guard->id() : 0; -} - -/*! - \fn QSize QGLFramebufferObject::size() const - - Returns the size of the texture attached to this framebuffer - object. -*/ -QSize QGLFramebufferObject::size() const -{ - Q_D(const QGLFramebufferObject); - return d->size; -} - -/*! - Returns the format of this framebuffer object. -*/ -QGLFramebufferObjectFormat QGLFramebufferObject::format() const -{ - Q_D(const QGLFramebufferObject); - return d->format; -} - -/*! - \fn QImage QGLFramebufferObject::toImage() const - - Returns the contents of this framebuffer object as a QImage. - - The returned image has a format of premultiplied ARGB32 or RGB32. The latter is used - only when internalTextureFormat() is set to \c GL_RGB. - - If the rendering in the framebuffer was not done with premultiplied alpha in mind, - create a wrapper QImage with a non-premultiplied format. This is necessary before - performing operations like QImage::save() because otherwise the image data would get - unpremultiplied, even though it was not premultiplied in the first place. To create - such a wrapper without performing a copy of the pixel data, do the following: - - \code - QImage fboImage(fbo.toImage()); - QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32); - \endcode - - On QNX the back buffer is not preserved when a buffer swap occures. So this function - might return old content. -*/ -QImage QGLFramebufferObject::toImage() const -{ - Q_D(const QGLFramebufferObject); - if (!d->valid) - return QImage(); - - // qt_gl_read_frame_buffer doesn't work on a multisample FBO - if (format().samples() != 0) { - QGLFramebufferObject temp(size(), QGLFramebufferObjectFormat()); - - QRect rect(QPoint(0, 0), size()); - blitFramebuffer(&temp, rect, const_cast<QGLFramebufferObject *>(this), rect); - - return temp.toImage(); - } - - bool wasBound = isBound(); - if (!wasBound) - const_cast<QGLFramebufferObject *>(this)->bind(); - QImage image = qt_gl_read_frame_buffer(d->size, format().internalTextureFormat() != GL_RGB, true); - if (!wasBound) - const_cast<QGLFramebufferObject *>(this)->release(); - - return image; -} - -Q_GLOBAL_STATIC(QGLEngineThreadStorage<QGL2PaintEngineEx>, qt_buffer_2_engine) - -/*! \reimp */ -QPaintEngine *QGLFramebufferObject::paintEngine() const -{ - Q_D(const QGLFramebufferObject); - if (d->engine) - return d->engine; - - QPaintEngine *engine = qt_buffer_2_engine()->engine(); - if (engine->isActive() && engine->paintDevice() != this) { - d->engine = new QGL2PaintEngineEx; - return d->engine; - } - return engine; -} - -/*! - \fn bool QGLFramebufferObject::bindDefault() - - Switches rendering back to the default, windowing system provided - framebuffer. - Returns \c true upon success, false otherwise. - - \sa bind(), release() -*/ -bool QGLFramebufferObject::bindDefault() -{ - QGLContext *ctx = const_cast<QGLContext *>(QGLContext::currentContext()); - - if (ctx) { - QOpenGLFunctions functions(ctx->contextHandle()); - if (!functions.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) - return false; - - ctx->d_ptr->setCurrentFbo(ctx->d_ptr->default_fbo); - functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->default_fbo); -#ifdef QT_DEBUG - } else { - qWarning("QGLFramebufferObject::bindDefault() called without current context."); -#endif - } - - return ctx != 0; -} - -/*! - \fn bool QGLFramebufferObject::hasOpenGLFramebufferObjects() - - Returns \c true if the OpenGL \c{GL_EXT_framebuffer_object} extension - is present on this system; otherwise returns \c false. -*/ -bool QGLFramebufferObject::hasOpenGLFramebufferObjects() -{ - return qgl_hasFeature(QOpenGLFunctions::Framebuffers); -} - -/*! - \since 4.4 - - Draws the given texture, \a textureId, to the given target rectangle, - \a target, in OpenGL model space. The \a textureTarget should be a 2D - texture target. - - The framebuffer object should be bound when calling this function. - - Equivalent to the corresponding QGLContext::drawTexture(). -*/ -void QGLFramebufferObject::drawTexture(const QRectF &target, GLuint textureId, GLenum textureTarget) -{ - const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(target, textureId, textureTarget); -} - -/*! - \since 4.4 - - Draws the given texture, \a textureId, at the given \a point in OpenGL - model space. The \a textureTarget should be a 2D texture target. - - The framebuffer object should be bound when calling this function. - - Equivalent to the corresponding QGLContext::drawTexture(). -*/ -void QGLFramebufferObject::drawTexture(const QPointF &point, GLuint textureId, GLenum textureTarget) -{ - const_cast<QGLContext *>(QGLContext::currentContext())->drawTexture(point, textureId, textureTarget); -} - -/*! \reimp */ -int QGLFramebufferObject::metric(PaintDeviceMetric metric) const -{ - Q_D(const QGLFramebufferObject); - - float dpmx = qt_defaultDpiX()*100./2.54; - float dpmy = qt_defaultDpiY()*100./2.54; - int w = d->size.width(); - int h = d->size.height(); - switch (metric) { - case PdmWidth: - return w; - - case PdmHeight: - return h; - - case PdmWidthMM: - return qRound(w * 1000 / dpmx); - - case PdmHeightMM: - return qRound(h * 1000 / dpmy); - - case PdmNumColors: - return 0; - - case PdmDepth: - return 32;//d->depth; - - case PdmDpiX: - return qRound(dpmx * 0.0254); - - case PdmDpiY: - return qRound(dpmy * 0.0254); - - case PdmPhysicalDpiX: - return qRound(dpmx * 0.0254); - - case PdmPhysicalDpiY: - return qRound(dpmy * 0.0254); - - case QPaintDevice::PdmDevicePixelRatio: - return 1; - - case QPaintDevice::PdmDevicePixelRatioScaled: - return 1 * QPaintDevice::devicePixelRatioFScale(); - - default: - qWarning("QGLFramebufferObject::metric(), Unhandled metric type: %d.\n", metric); - break; - } - return 0; -} - -/*! - \fn GLuint QGLFramebufferObject::handle() const - - Returns the GL framebuffer object handle for this framebuffer - object (returned by the \c{glGenFrameBuffersEXT()} function). This - handle can be used to attach new images or buffers to the - framebuffer. The user is responsible for cleaning up and - destroying these objects. -*/ -GLuint QGLFramebufferObject::handle() const -{ - Q_D(const QGLFramebufferObject); - return d->fbo(); -} - -/*! \fn int QGLFramebufferObject::devType() const - \internal -*/ - - -/*! - Returns the status of the depth and stencil buffers attached to - this framebuffer object. -*/ - -QGLFramebufferObject::Attachment QGLFramebufferObject::attachment() const -{ - Q_D(const QGLFramebufferObject); - if (d->valid) - return d->fbo_attachment; - return NoAttachment; -} - -/*! - \since 4.5 - - Returns \c true if the framebuffer object is currently bound to a context, - otherwise false is returned. -*/ - -bool QGLFramebufferObject::isBound() const -{ - Q_D(const QGLFramebufferObject); - const QGLContext *current = QGLContext::currentContext(); - if (current) { - current->d_ptr->refreshCurrentFbo(); - return current->d_ptr->current_fbo == d->fbo(); - } - - return false; -} - -/*! - \fn bool QGLFramebufferObject::hasOpenGLFramebufferBlit() - - \since 4.6 - - Returns \c true if the OpenGL \c{GL_EXT_framebuffer_blit} extension - is present on this system; otherwise returns \c false. - - \sa blitFramebuffer() -*/ -bool QGLFramebufferObject::hasOpenGLFramebufferBlit() -{ - return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); -} - -/*! - \since 4.6 - - Blits from the \a sourceRect rectangle in the \a source framebuffer - object to the \a targetRect rectangle in the \a target framebuffer object. - - If \a source or \a target is 0, the default framebuffer will be used - instead of a framebuffer object as source or target respectively. - - The \a buffers parameter should be a mask consisting of any combination of - \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and - \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both - in the source and target buffers is ignored. - - The \a sourceRect and \a targetRect rectangles may have different sizes; - in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or - \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to - \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest - interpolation should be used when scaling is performed. - - If \a source equals \a target a copy is performed within the same buffer. - Results are undefined if the source and target rectangles overlap and - have different sizes. The sizes must also be the same if any of the - framebuffer objects are multisample framebuffers. - - Note that the scissor test will restrict the blit area if enabled. - - This function will have no effect unless hasOpenGLFramebufferBlit() returns - true. - - \sa hasOpenGLFramebufferBlit() -*/ -void QGLFramebufferObject::blitFramebuffer(QGLFramebufferObject *target, const QRect &targetRect, - QGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers, - GLenum filter) -{ - const QGLContext *ctx = QGLContext::currentContext(); - if (!ctx || !ctx->contextHandle()) - return; - - QOpenGLExtensions functions(ctx->contextHandle()); - if (!functions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) - return; - - QSurface *surface = ctx->contextHandle()->surface(); - - const int height = static_cast<QWindow *>(surface)->height(); - - const int sh = source ? source->height() : height; - const int th = target ? target->height() : height; - - const int sx0 = sourceRect.left(); - const int sx1 = sourceRect.left() + sourceRect.width(); - const int sy0 = sh - (sourceRect.top() + sourceRect.height()); - const int sy1 = sh - sourceRect.top(); - - const int tx0 = targetRect.left(); - const int tx1 = targetRect.left() + targetRect.width(); - const int ty0 = th - (targetRect.top() + targetRect.height()); - const int ty1 = th - targetRect.top(); - - ctx->d_ptr->refreshCurrentFbo(); - - functions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0); - functions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0); - - functions.glBlitFramebuffer(sx0, sy0, sx1, sy1, - tx0, ty0, tx1, ty1, - buffers, filter); - - functions.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_ptr->current_fbo); -} - -QT_END_NAMESPACE |