From fcaa7506ba1823c5af84341ced3914ea0099b446 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Fri, 17 Jan 2020 14:15:29 +0100 Subject: Move QOpenGLTextureBlitter from QtGui to QtOpenGL Task-number: QTBUG-74409 Change-Id: Ie4a3dfd01ba44715de6da71c4420fe9a95a0c242 Reviewed-by: Qt CI Bot Reviewed-by: Laszlo Agocs --- src/gui/opengl/opengl.pri | 2 - src/gui/opengl/qopengltextureblitter.cpp | 682 --------------------- src/gui/opengl/qopengltextureblitter.h | 94 --- src/opengl/opengl.pro | 2 + src/opengl/qopengltextureblitter.cpp | 682 +++++++++++++++++++++ src/opengl/qopengltextureblitter.h | 90 +++ src/opengl/qopenglwindow.cpp | 2 +- .../platformcompositor/platformcompositor.pro | 2 +- .../platformcompositor/qopenglcompositor_p.h | 2 +- .../qplatformbackingstoreopenglsupport.cpp | 3 +- src/plugins/platforms/wasm/qwasmcompositor.cpp | 1 - src/plugins/platforms/wasm/qwasmcompositor.h | 3 +- tests/auto/gui/qopengl/tst_qopengl.cpp | 2 +- 13 files changed, 780 insertions(+), 787 deletions(-) delete mode 100644 src/gui/opengl/qopengltextureblitter.cpp delete mode 100644 src/gui/opengl/qopengltextureblitter.h create mode 100644 src/opengl/qopengltextureblitter.cpp create mode 100644 src/opengl/qopengltextureblitter.h diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index f1e2019417..8d91a9e4b2 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -16,7 +16,6 @@ qtConfig(opengl) { opengl/qopenglversionfunctions.h \ opengl/qopenglversionfunctionsfactory_p.h \ opengl/qopenglvertexarrayobject.h \ - opengl/qopengltextureblitter.h \ opengl/qopenglextrafunctions.h \ opengl/qopenglprogrambinarycache_p.h @@ -28,7 +27,6 @@ qtConfig(opengl) { opengl/qopenglversionfunctions.cpp \ opengl/qopenglversionfunctionsfactory.cpp \ opengl/qopenglvertexarrayobject.cpp \ - opengl/qopengltextureblitter.cpp \ opengl/qopenglprogrambinarycache.cpp !qtConfig(opengles2) { diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp deleted file mode 100644 index b709f2f639..0000000000 --- a/src/gui/opengl/qopengltextureblitter.cpp +++ /dev/null @@ -1,682 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui 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 "qopengltextureblitter.h" - -#include -#include -#include -#include -#include - -#ifndef GL_TEXTURE_EXTERNAL_OES -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 -#endif - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLTextureBlitter - \brief The QOpenGLTextureBlitter class provides a convenient way to draw textured quads via OpenGL. - \since 5.8 - \ingroup painting-3D - \inmodule QtGui - - Drawing textured quads, in order to get the contents of a texture - onto the screen, is a common operation when developing 2D user - interfaces. QOpenGLTextureBlitter provides a convenience class to - avoid repeating vertex data, shader sources, buffer and program - management and matrix calculations. - - For example, a QOpenGLWidget subclass can do the following to draw - the contents rendered into a framebuffer at the pixel position \c{(x, y)}: - - \code - void OpenGLWidget::initializeGL() - { - m_blitter.create(); - m_fbo = new QOpenGLFramebufferObject(size); - } - - void OpenGLWidget::paintGL() - { - m_fbo->bind(); - // update offscreen content - m_fbo->release(); - - m_blitter.bind(); - const QRect targetRect(QPoint(x, y), m_fbo->size()); - const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), m_fbo->size())); - m_blitter.blit(m_fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft); - m_blitter.release(); - } - \endcode - - The blitter implements GLSL shaders both for GLSL 1.00 (suitable - for OpenGL (ES) 2.x and compatibility profiles of newer OpenGL - versions) and version 150 (suitable for core profile contexts with - OpenGL 3.2 and newer). - */ - -static const char vertex_shader150[] = - "#version 150 core\n" - "in vec3 vertexCoord;" - "in vec2 textureCoord;" - "out vec2 uv;" - "uniform mat4 vertexTransform;" - "uniform mat3 textureTransform;" - "void main() {" - " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" - " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" - "}"; - -static const char fragment_shader150[] = - "#version 150 core\n" - "in vec2 uv;" - "out vec4 fragcolor;" - "uniform sampler2D textureSampler;" - "uniform bool swizzle;" - "uniform float opacity;" - "void main() {" - " vec4 tmpFragColor = texture(textureSampler, uv);" - " tmpFragColor.a *= opacity;" - " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;" - "}"; - -static const char vertex_shader[] = - "attribute highp vec3 vertexCoord;" - "attribute highp vec2 textureCoord;" - "varying highp vec2 uv;" - "uniform highp mat4 vertexTransform;" - "uniform highp mat3 textureTransform;" - "void main() {" - " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" - " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" - "}"; - -static const char fragment_shader[] = - "varying highp vec2 uv;" - "uniform sampler2D textureSampler;" - "uniform bool swizzle;" - "uniform highp float opacity;" - "void main() {" - " highp vec4 tmpFragColor = texture2D(textureSampler,uv);" - " tmpFragColor.a *= opacity;" - " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" - "}"; - -static const char fragment_shader_external_oes[] = - "#extension GL_OES_EGL_image_external : require\n" - "varying highp vec2 uv;" - "uniform samplerExternalOES textureSampler;\n" - "uniform bool swizzle;" - "uniform highp float opacity;" - "void main() {" - " highp vec4 tmpFragColor = texture2D(textureSampler, uv);" - " tmpFragColor.a *= opacity;" - " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" - "}"; - -static const GLfloat vertex_buffer_data[] = { - -1,-1, 0, - -1, 1, 0, - 1,-1, 0, - -1, 1, 0, - 1,-1, 0, - 1, 1, 0 -}; - -static const GLfloat texture_buffer_data[] = { - 0, 0, - 0, 1, - 1, 0, - 0, 1, - 1, 0, - 1, 1 -}; - -class TextureBinder -{ -public: - TextureBinder(GLenum target, GLuint textureId) : m_target(target) - { - QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, textureId); - } - ~TextureBinder() - { - QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, 0); - } - -private: - GLenum m_target; -}; - -class QOpenGLTextureBlitterPrivate -{ -public: - enum TextureMatrixUniform { - User, - Identity, - IdentityFlipped - }; - - enum ProgramIndex { - TEXTURE_2D, - TEXTURE_EXTERNAL_OES - }; - - QOpenGLTextureBlitterPrivate() : - swizzle(false), - opacity(1.0f), - vao(new QOpenGLVertexArrayObject), - currentTarget(TEXTURE_2D) - { } - - bool buildProgram(ProgramIndex idx, const char *vs, const char *fs); - - void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform); - void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin); - - void prepareProgram(const QMatrix4x4 &vertexTransform); - - QOpenGLBuffer vertexBuffer; - QOpenGLBuffer textureBuffer; - struct Program { - Program() : - vertexCoordAttribPos(0), - vertexTransformUniformPos(0), - textureCoordAttribPos(0), - textureTransformUniformPos(0), - swizzleUniformPos(0), - opacityUniformPos(0), - swizzle(false), - opacity(0.0f), - textureMatrixUniformState(User) - { } - QScopedPointer glProgram; - GLuint vertexCoordAttribPos; - GLuint vertexTransformUniformPos; - GLuint textureCoordAttribPos; - GLuint textureTransformUniformPos; - GLuint swizzleUniformPos; - GLuint opacityUniformPos; - bool swizzle; - float opacity; - TextureMatrixUniform textureMatrixUniformState; - } programs[2]; - bool swizzle; - float opacity; - QScopedPointer vao; - GLenum currentTarget; -}; - -static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target) -{ - switch (target) { - case GL_TEXTURE_2D: - return QOpenGLTextureBlitterPrivate::TEXTURE_2D; - case GL_TEXTURE_EXTERNAL_OES: - return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES; - default: - qWarning("Unsupported texture target 0x%x", target); - return QOpenGLTextureBlitterPrivate::TEXTURE_2D; - } -} - -void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform) -{ - Program *program = &programs[targetToProgramIndex(currentTarget)]; - - vertexBuffer.bind(); - program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); - program->glProgram->enableAttributeArray(program->vertexCoordAttribPos); - vertexBuffer.release(); - - program->glProgram->setUniformValue(program->vertexTransformUniformPos, vertexTransform); - - textureBuffer.bind(); - program->glProgram->setAttributeBuffer(program->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); - program->glProgram->enableAttributeArray(program->textureCoordAttribPos); - textureBuffer.release(); - - if (swizzle != program->swizzle) { - program->glProgram->setUniformValue(program->swizzleUniformPos, swizzle); - program->swizzle = swizzle; - } - - if (opacity != program->opacity) { - program->glProgram->setUniformValue(program->opacityUniformPos, opacity); - program->opacity = opacity; - } -} - -void QOpenGLTextureBlitterPrivate::blit(GLuint texture, - const QMatrix4x4 &vertexTransform, - const QMatrix3x3 &textureTransform) -{ - TextureBinder binder(currentTarget, texture); - prepareProgram(vertexTransform); - - Program *program = &programs[targetToProgramIndex(currentTarget)]; - program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform); - program->textureMatrixUniformState = User; - - QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); -} - -void QOpenGLTextureBlitterPrivate::blit(GLuint texture, - const QMatrix4x4 &vertexTransform, - QOpenGLTextureBlitter::Origin origin) -{ - TextureBinder binder(currentTarget, texture); - prepareProgram(vertexTransform); - - Program *program = &programs[targetToProgramIndex(currentTarget)]; - if (origin == QOpenGLTextureBlitter::OriginTopLeft) { - if (program->textureMatrixUniformState != IdentityFlipped) { - QMatrix3x3 flipped; - flipped(1,1) = -1; - flipped(1,2) = 1; - program->glProgram->setUniformValue(program->textureTransformUniformPos, flipped); - program->textureMatrixUniformState = IdentityFlipped; - } - } else if (program->textureMatrixUniformState != Identity) { - program->glProgram->setUniformValue(program->textureTransformUniformPos, QMatrix3x3()); - program->textureMatrixUniformState = Identity; - } - - QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); -} - -bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs, const char *fs) -{ - Program *p = &programs[idx]; - - p->glProgram.reset(new QOpenGLShaderProgram); - - p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs); - p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs); - p->glProgram->link(); - if (!p->glProgram->isLinked()) { - qWarning() << "Could not link shader program:\n" << p->glProgram->log(); - return false; - } - - p->glProgram->bind(); - - p->vertexCoordAttribPos = p->glProgram->attributeLocation("vertexCoord"); - p->vertexTransformUniformPos = p->glProgram->uniformLocation("vertexTransform"); - p->textureCoordAttribPos = p->glProgram->attributeLocation("textureCoord"); - p->textureTransformUniformPos = p->glProgram->uniformLocation("textureTransform"); - p->swizzleUniformPos = p->glProgram->uniformLocation("swizzle"); - p->opacityUniformPos = p->glProgram->uniformLocation("opacity"); - - p->glProgram->setUniformValue(p->swizzleUniformPos, false); - - // minmize state left set after a create() - p->glProgram->release(); - - return true; -} - -/*! - Constructs a new QOpenGLTextureBlitter instance. - - \note no graphics resources are initialized in the - constructor. This makes it safe to place plain - QOpenGLTextureBlitter members into classes because the actual - initialization that depends on the OpenGL context happens only in - create(). - */ -QOpenGLTextureBlitter::QOpenGLTextureBlitter() - : d_ptr(new QOpenGLTextureBlitterPrivate) -{ -} - -/*! - Destructs the instance. - - \note When the OpenGL context - or a context sharing resources - with it - that was current when calling create() is not current, - graphics resources will not be released. Therefore, it is - recommended to call destroy() manually instead of relying on the - destructor to perform OpenGL resource cleanup. - */ -QOpenGLTextureBlitter::~QOpenGLTextureBlitter() -{ - destroy(); -} - -/*! - Initializes the graphics resources used by the blitter. - - \return \c true if successful, \c false if there was a - failure. Failures can occur when there is no OpenGL context - current on the current thread, or when shader compilation fails - for some reason. - - \sa isCreated(), destroy() - */ -bool QOpenGLTextureBlitter::create() -{ - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - if (!currentContext) - return false; - - Q_D(QOpenGLTextureBlitter); - - if (d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram) - return true; - - QSurfaceFormat format = currentContext->format(); - if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150)) - return false; - } else { - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader)) - return false; - if (supportsExternalOESTarget()) - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes)) - return false; - } - - // Create and bind the VAO, if supported. - QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data()); - - d->vertexBuffer.create(); - d->vertexBuffer.bind(); - d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data)); - d->vertexBuffer.release(); - - d->textureBuffer.create(); - d->textureBuffer.bind(); - d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data)); - d->textureBuffer.release(); - - return true; -} - -/*! - \return \c true if create() was called and succeeded. \c false otherwise. - - \sa create(), destroy() - */ -bool QOpenGLTextureBlitter::isCreated() const -{ - Q_D(const QOpenGLTextureBlitter); - return d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram; -} - -/*! - Frees all graphics resources held by the blitter. Assumes that - the OpenGL context, or another context sharing resources with it, - that was current on the thread when invoking create() is current. - - The function has no effect when the blitter is not in created state. - - \sa create() - */ -void QOpenGLTextureBlitter::destroy() -{ - if (!isCreated()) - return; - Q_D(QOpenGLTextureBlitter); - d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset(); - d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset(); - d->vertexBuffer.destroy(); - d->textureBuffer.destroy(); - d->vao.reset(); -} - -/*! - \return \c true when bind() accepts \c GL_TEXTURE_EXTERNAL_OES as - its target argument. - - \sa bind(), blit() - */ -bool QOpenGLTextureBlitter::supportsExternalOESTarget() const -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external"); -} - -/*! - Binds the graphics resources used by the blitter. This must be - called before calling blit(). Code modifying the OpenGL state - should be avoided between the call to bind() and blit() because - otherwise conflicts may arise. - - \a target is the texture target for the source texture and must be - either \c GL_TEXTURE_2D or \c GL_OES_EGL_image_external. - - \sa release(), blit() - */ -void QOpenGLTextureBlitter::bind(GLenum target) -{ - Q_D(QOpenGLTextureBlitter); - - if (d->vao->isCreated()) - d->vao->bind(); - - d->currentTarget = target; - QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)]; - p->glProgram->bind(); - - d->vertexBuffer.bind(); - p->glProgram->setAttributeBuffer(p->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); - p->glProgram->enableAttributeArray(p->vertexCoordAttribPos); - d->vertexBuffer.release(); - - d->textureBuffer.bind(); - p->glProgram->setAttributeBuffer(p->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); - p->glProgram->enableAttributeArray(p->textureCoordAttribPos); - d->textureBuffer.release(); -} - -/*! - Unbinds the graphics resources used by the blitter. - - \sa bind() - */ -void QOpenGLTextureBlitter::release() -{ - Q_D(QOpenGLTextureBlitter); - d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release(); - if (d->vao->isCreated()) - d->vao->release(); -} - -/*! - Sets whether swizzling is enabled for the red and blue color channels to - \a swizzle. An BGRA to RGBA conversion (occurring in the shader on - the GPU, instead of a slow CPU-side transformation) can be useful - when the source texture contains data from a QImage with a format - like QImage::Format_ARGB32 which maps to BGRA on little endian - systems. - - By default the red-blue swizzle is disabled since this is what a - texture attached to an framebuffer object or a texture based on a - byte ordered QImage format (like QImage::Format_RGBA8888) needs. - */ -void QOpenGLTextureBlitter::setRedBlueSwizzle(bool swizzle) -{ - Q_D(QOpenGLTextureBlitter); - d->swizzle = swizzle; -} - -/*! - Changes the opacity to \a opacity. The default opacity is 1.0. - - \note the blitter does not alter the blend state. It is up to the - caller of blit() to ensure the correct blend settings are active. - - */ -void QOpenGLTextureBlitter::setOpacity(float opacity) -{ - Q_D(QOpenGLTextureBlitter); - d->opacity = opacity; -} - -/*! - \enum QOpenGLTextureBlitter::Origin - - \value OriginBottomLeft Indicates that the data in the texture - follows the OpenGL convention of coordinate systems, meaning Y is - running from bottom to top. - - \value OriginTopLeft Indicates that the data in the texture has Y - running from top to bottom, which is typical with regular, - unflipped image data. - - \sa blit() - */ - -/*! - Performs the blit with the source texture \a texture. - - \a targetTransform specifies the transformation applied. This is - usually generated by the targetTransform() helper function. - - \a sourceOrigin specifies if the image data needs flipping. When - \a texture corresponds to a texture attached to an FBO pass - OriginBottomLeft. On the other hand, when \a texture is based on - unflipped image data, pass OriginTopLeft. This is more efficient - than using QImage::mirrored(). - - \sa targetTransform(), Origin, bind() - */ -void QOpenGLTextureBlitter::blit(GLuint texture, - const QMatrix4x4 &targetTransform, - Origin sourceOrigin) -{ - Q_D(QOpenGLTextureBlitter); - d->blit(texture,targetTransform, sourceOrigin); -} - -/*! - Performs the blit with the source texture \a texture. - - \a targetTransform specifies the transformation applied. This is - usually generated by the targetTransform() helper function. - - \a sourceTransform specifies the transformation applied to the - source. This allows using only a sub-rect of the source - texture. This is usually generated by the sourceTransform() helper - function. - - \sa sourceTransform(), targetTransform(), Origin, bind() - */ -void QOpenGLTextureBlitter::blit(GLuint texture, - const QMatrix4x4 &targetTransform, - const QMatrix3x3 &sourceTransform) -{ - Q_D(QOpenGLTextureBlitter); - d->blit(texture, targetTransform, sourceTransform); -} - -/*! - Calculates a target transform suitable for blit(). - - \a target is the target rectangle in pixels. \a viewport describes - the source dimensions and will in most cases be set to (0, 0, - image width, image height). - - For unscaled output the size of \a target and \a viewport should - match. - - \sa blit() - */ -QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, - const QRect &viewport) -{ - qreal x_scale = target.width() / viewport.width(); - qreal y_scale = target.height() / viewport.height(); - - const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft(); - qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2); - qreal y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2); - - QMatrix4x4 matrix; - matrix(0,3) = x_translate; - matrix(1,3) = y_translate; - - matrix(0,0) = x_scale; - matrix(1,1) = y_scale; - - return matrix; -} - -/*! - Calculates a 3x3 matrix suitable as the input to blit(). This is - used when only a part of the texture is to be used in the blit. - - \a subTexture is the desired source rectangle in pixels, \a - textureSize is the full width and height of the texture data. \a - origin specifies the orientation of the image data when it comes - to the Y axis. - - \sa blit(), Origin - */ -QMatrix3x3 QOpenGLTextureBlitter::sourceTransform(const QRectF &subTexture, - const QSize &textureSize, - Origin origin) -{ - qreal x_scale = subTexture.width() / textureSize.width(); - qreal y_scale = subTexture.height() / textureSize.height(); - - const QPointF topLeft = subTexture.topLeft(); - qreal x_translate = topLeft.x() / textureSize.width(); - qreal y_translate = topLeft.y() / textureSize.height(); - - if (origin == OriginTopLeft) { - y_scale = -y_scale; - y_translate = 1 - y_translate; - } - - QMatrix3x3 matrix; - matrix(0,2) = x_translate; - matrix(1,2) = y_translate; - - matrix(0,0) = x_scale; - matrix(1,1) = y_scale; - - return matrix; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltextureblitter.h b/src/gui/opengl/qopengltextureblitter.h deleted file mode 100644 index 2f7c6b1a0a..0000000000 --- a/src/gui/opengl/qopengltextureblitter.h +++ /dev/null @@ -1,94 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui 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$ -** -****************************************************************************/ - -#ifndef QOPENGLTEXTUREBLITTER_H -#define QOPENGLTEXTUREBLITTER_H - -#include - -#ifndef QT_NO_OPENGL - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QOpenGLTextureBlitterPrivate; - -class Q_GUI_EXPORT QOpenGLTextureBlitter -{ -public: - QOpenGLTextureBlitter(); - ~QOpenGLTextureBlitter(); - - enum Origin { - OriginBottomLeft, - OriginTopLeft - }; - - bool create(); - bool isCreated() const; - void destroy(); - - bool supportsExternalOESTarget() const; - - void bind(GLenum target = GL_TEXTURE_2D); - void release(); - - void setRedBlueSwizzle(bool swizzle); - void setOpacity(float opacity); - - void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin); - void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); - - static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport); - static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin); - -private: - Q_DISABLE_COPY(QOpenGLTextureBlitter) - Q_DECLARE_PRIVATE(QOpenGLTextureBlitter) - QScopedPointer d_ptr; -}; - -QT_END_NAMESPACE - -#endif - -#endif //QOPENGLTEXTUREBLITTER_H diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index ba9590ec07..2a5d7edbee 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -24,6 +24,7 @@ HEADERS += \ qopengltexture.h \ qopengltexture_p.h \ qopengltexturehelper_p.h \ + qopengltextureblitter.h \ qopengltexturecache_p.h \ qopengltextureglyphcache_p.h \ qopengltextureuploader_p.h \ @@ -40,6 +41,7 @@ SOURCES += \ qopenglpixeltransferoptions.cpp \ qopengltexture.cpp \ qopengltexturehelper.cpp \ + qopengltextureblitter.cpp \ qopengltexturecache.cpp \ qopengltextureglyphcache.cpp \ qopengltextureuploader.cpp \ diff --git a/src/opengl/qopengltextureblitter.cpp b/src/opengl/qopengltextureblitter.cpp new file mode 100644 index 0000000000..ba2eaf7754 --- /dev/null +++ b/src/opengl/qopengltextureblitter.cpp @@ -0,0 +1,682 @@ +/**************************************************************************** +** +** 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 "qopengltextureblitter.h" + +#include +#include +#include +#include +#include + +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + +QT_BEGIN_NAMESPACE + +/*! + \class QOpenGLTextureBlitter + \brief The QOpenGLTextureBlitter class provides a convenient way to draw textured quads via OpenGL. + \since 5.8 + \ingroup painting-3D + \inmodule QtOpenGL + + Drawing textured quads, in order to get the contents of a texture + onto the screen, is a common operation when developing 2D user + interfaces. QOpenGLTextureBlitter provides a convenience class to + avoid repeating vertex data, shader sources, buffer and program + management and matrix calculations. + + For example, a QOpenGLWidget subclass can do the following to draw + the contents rendered into a framebuffer at the pixel position \c{(x, y)}: + + \code + void OpenGLWidget::initializeGL() + { + m_blitter.create(); + m_fbo = new QOpenGLFramebufferObject(size); + } + + void OpenGLWidget::paintGL() + { + m_fbo->bind(); + // update offscreen content + m_fbo->release(); + + m_blitter.bind(); + const QRect targetRect(QPoint(x, y), m_fbo->size()); + const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), m_fbo->size())); + m_blitter.blit(m_fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft); + m_blitter.release(); + } + \endcode + + The blitter implements GLSL shaders both for GLSL 1.00 (suitable + for OpenGL (ES) 2.x and compatibility profiles of newer OpenGL + versions) and version 150 (suitable for core profile contexts with + OpenGL 3.2 and newer). + */ + +static const char vertex_shader150[] = + "#version 150 core\n" + "in vec3 vertexCoord;" + "in vec2 textureCoord;" + "out vec2 uv;" + "uniform mat4 vertexTransform;" + "uniform mat3 textureTransform;" + "void main() {" + " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" + " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" + "}"; + +static const char fragment_shader150[] = + "#version 150 core\n" + "in vec2 uv;" + "out vec4 fragcolor;" + "uniform sampler2D textureSampler;" + "uniform bool swizzle;" + "uniform float opacity;" + "void main() {" + " vec4 tmpFragColor = texture(textureSampler, uv);" + " tmpFragColor.a *= opacity;" + " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;" + "}"; + +static const char vertex_shader[] = + "attribute highp vec3 vertexCoord;" + "attribute highp vec2 textureCoord;" + "varying highp vec2 uv;" + "uniform highp mat4 vertexTransform;" + "uniform highp mat3 textureTransform;" + "void main() {" + " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" + " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" + "}"; + +static const char fragment_shader[] = + "varying highp vec2 uv;" + "uniform sampler2D textureSampler;" + "uniform bool swizzle;" + "uniform highp float opacity;" + "void main() {" + " highp vec4 tmpFragColor = texture2D(textureSampler,uv);" + " tmpFragColor.a *= opacity;" + " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" + "}"; + +static const char fragment_shader_external_oes[] = + "#extension GL_OES_EGL_image_external : require\n" + "varying highp vec2 uv;" + "uniform samplerExternalOES textureSampler;\n" + "uniform bool swizzle;" + "uniform highp float opacity;" + "void main() {" + " highp vec4 tmpFragColor = texture2D(textureSampler, uv);" + " tmpFragColor.a *= opacity;" + " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" + "}"; + +static const GLfloat vertex_buffer_data[] = { + -1,-1, 0, + -1, 1, 0, + 1,-1, 0, + -1, 1, 0, + 1,-1, 0, + 1, 1, 0 +}; + +static const GLfloat texture_buffer_data[] = { + 0, 0, + 0, 1, + 1, 0, + 0, 1, + 1, 0, + 1, 1 +}; + +class TextureBinder +{ +public: + TextureBinder(GLenum target, GLuint textureId) : m_target(target) + { + QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, textureId); + } + ~TextureBinder() + { + QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, 0); + } + +private: + GLenum m_target; +}; + +class QOpenGLTextureBlitterPrivate +{ +public: + enum TextureMatrixUniform { + User, + Identity, + IdentityFlipped + }; + + enum ProgramIndex { + TEXTURE_2D, + TEXTURE_EXTERNAL_OES + }; + + QOpenGLTextureBlitterPrivate() : + swizzle(false), + opacity(1.0f), + vao(new QOpenGLVertexArrayObject), + currentTarget(TEXTURE_2D) + { } + + bool buildProgram(ProgramIndex idx, const char *vs, const char *fs); + + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform); + void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin); + + void prepareProgram(const QMatrix4x4 &vertexTransform); + + QOpenGLBuffer vertexBuffer; + QOpenGLBuffer textureBuffer; + struct Program { + Program() : + vertexCoordAttribPos(0), + vertexTransformUniformPos(0), + textureCoordAttribPos(0), + textureTransformUniformPos(0), + swizzleUniformPos(0), + opacityUniformPos(0), + swizzle(false), + opacity(0.0f), + textureMatrixUniformState(User) + { } + QScopedPointer glProgram; + GLuint vertexCoordAttribPos; + GLuint vertexTransformUniformPos; + GLuint textureCoordAttribPos; + GLuint textureTransformUniformPos; + GLuint swizzleUniformPos; + GLuint opacityUniformPos; + bool swizzle; + float opacity; + TextureMatrixUniform textureMatrixUniformState; + } programs[2]; + bool swizzle; + float opacity; + QScopedPointer vao; + GLenum currentTarget; +}; + +static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target) +{ + switch (target) { + case GL_TEXTURE_2D: + return QOpenGLTextureBlitterPrivate::TEXTURE_2D; + case GL_TEXTURE_EXTERNAL_OES: + return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES; + default: + qWarning("Unsupported texture target 0x%x", target); + return QOpenGLTextureBlitterPrivate::TEXTURE_2D; + } +} + +void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform) +{ + Program *program = &programs[targetToProgramIndex(currentTarget)]; + + vertexBuffer.bind(); + program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + program->glProgram->enableAttributeArray(program->vertexCoordAttribPos); + vertexBuffer.release(); + + program->glProgram->setUniformValue(program->vertexTransformUniformPos, vertexTransform); + + textureBuffer.bind(); + program->glProgram->setAttributeBuffer(program->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + program->glProgram->enableAttributeArray(program->textureCoordAttribPos); + textureBuffer.release(); + + if (swizzle != program->swizzle) { + program->glProgram->setUniformValue(program->swizzleUniformPos, swizzle); + program->swizzle = swizzle; + } + + if (opacity != program->opacity) { + program->glProgram->setUniformValue(program->opacityUniformPos, opacity); + program->opacity = opacity; + } +} + +void QOpenGLTextureBlitterPrivate::blit(GLuint texture, + const QMatrix4x4 &vertexTransform, + const QMatrix3x3 &textureTransform) +{ + TextureBinder binder(currentTarget, texture); + prepareProgram(vertexTransform); + + Program *program = &programs[targetToProgramIndex(currentTarget)]; + program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform); + program->textureMatrixUniformState = User; + + QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void QOpenGLTextureBlitterPrivate::blit(GLuint texture, + const QMatrix4x4 &vertexTransform, + QOpenGLTextureBlitter::Origin origin) +{ + TextureBinder binder(currentTarget, texture); + prepareProgram(vertexTransform); + + Program *program = &programs[targetToProgramIndex(currentTarget)]; + if (origin == QOpenGLTextureBlitter::OriginTopLeft) { + if (program->textureMatrixUniformState != IdentityFlipped) { + QMatrix3x3 flipped; + flipped(1,1) = -1; + flipped(1,2) = 1; + program->glProgram->setUniformValue(program->textureTransformUniformPos, flipped); + program->textureMatrixUniformState = IdentityFlipped; + } + } else if (program->textureMatrixUniformState != Identity) { + program->glProgram->setUniformValue(program->textureTransformUniformPos, QMatrix3x3()); + program->textureMatrixUniformState = Identity; + } + + QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); +} + +bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs, const char *fs) +{ + Program *p = &programs[idx]; + + p->glProgram.reset(new QOpenGLShaderProgram); + + p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs); + p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs); + p->glProgram->link(); + if (!p->glProgram->isLinked()) { + qWarning() << "Could not link shader program:\n" << p->glProgram->log(); + return false; + } + + p->glProgram->bind(); + + p->vertexCoordAttribPos = p->glProgram->attributeLocation("vertexCoord"); + p->vertexTransformUniformPos = p->glProgram->uniformLocation("vertexTransform"); + p->textureCoordAttribPos = p->glProgram->attributeLocation("textureCoord"); + p->textureTransformUniformPos = p->glProgram->uniformLocation("textureTransform"); + p->swizzleUniformPos = p->glProgram->uniformLocation("swizzle"); + p->opacityUniformPos = p->glProgram->uniformLocation("opacity"); + + p->glProgram->setUniformValue(p->swizzleUniformPos, false); + + // minmize state left set after a create() + p->glProgram->release(); + + return true; +} + +/*! + Constructs a new QOpenGLTextureBlitter instance. + + \note no graphics resources are initialized in the + constructor. This makes it safe to place plain + QOpenGLTextureBlitter members into classes because the actual + initialization that depends on the OpenGL context happens only in + create(). + */ +QOpenGLTextureBlitter::QOpenGLTextureBlitter() + : d_ptr(new QOpenGLTextureBlitterPrivate) +{ +} + +/*! + Destructs the instance. + + \note When the OpenGL context - or a context sharing resources + with it - that was current when calling create() is not current, + graphics resources will not be released. Therefore, it is + recommended to call destroy() manually instead of relying on the + destructor to perform OpenGL resource cleanup. + */ +QOpenGLTextureBlitter::~QOpenGLTextureBlitter() +{ + destroy(); +} + +/*! + Initializes the graphics resources used by the blitter. + + \return \c true if successful, \c false if there was a + failure. Failures can occur when there is no OpenGL context + current on the current thread, or when shader compilation fails + for some reason. + + \sa isCreated(), destroy() + */ +bool QOpenGLTextureBlitter::create() +{ + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + if (!currentContext) + return false; + + Q_D(QOpenGLTextureBlitter); + + if (d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram) + return true; + + QSurfaceFormat format = currentContext->format(); + if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150)) + return false; + } else { + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader)) + return false; + if (supportsExternalOESTarget()) + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes)) + return false; + } + + // Create and bind the VAO, if supported. + QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data()); + + d->vertexBuffer.create(); + d->vertexBuffer.bind(); + d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data)); + d->vertexBuffer.release(); + + d->textureBuffer.create(); + d->textureBuffer.bind(); + d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data)); + d->textureBuffer.release(); + + return true; +} + +/*! + \return \c true if create() was called and succeeded. \c false otherwise. + + \sa create(), destroy() + */ +bool QOpenGLTextureBlitter::isCreated() const +{ + Q_D(const QOpenGLTextureBlitter); + return d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram; +} + +/*! + Frees all graphics resources held by the blitter. Assumes that + the OpenGL context, or another context sharing resources with it, + that was current on the thread when invoking create() is current. + + The function has no effect when the blitter is not in created state. + + \sa create() + */ +void QOpenGLTextureBlitter::destroy() +{ + if (!isCreated()) + return; + Q_D(QOpenGLTextureBlitter); + d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset(); + d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset(); + d->vertexBuffer.destroy(); + d->textureBuffer.destroy(); + d->vao.reset(); +} + +/*! + \return \c true when bind() accepts \c GL_TEXTURE_EXTERNAL_OES as + its target argument. + + \sa bind(), blit() + */ +bool QOpenGLTextureBlitter::supportsExternalOESTarget() const +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external"); +} + +/*! + Binds the graphics resources used by the blitter. This must be + called before calling blit(). Code modifying the OpenGL state + should be avoided between the call to bind() and blit() because + otherwise conflicts may arise. + + \a target is the texture target for the source texture and must be + either \c GL_TEXTURE_2D or \c GL_OES_EGL_image_external. + + \sa release(), blit() + */ +void QOpenGLTextureBlitter::bind(GLenum target) +{ + Q_D(QOpenGLTextureBlitter); + + if (d->vao->isCreated()) + d->vao->bind(); + + d->currentTarget = target; + QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)]; + p->glProgram->bind(); + + d->vertexBuffer.bind(); + p->glProgram->setAttributeBuffer(p->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); + p->glProgram->enableAttributeArray(p->vertexCoordAttribPos); + d->vertexBuffer.release(); + + d->textureBuffer.bind(); + p->glProgram->setAttributeBuffer(p->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); + p->glProgram->enableAttributeArray(p->textureCoordAttribPos); + d->textureBuffer.release(); +} + +/*! + Unbinds the graphics resources used by the blitter. + + \sa bind() + */ +void QOpenGLTextureBlitter::release() +{ + Q_D(QOpenGLTextureBlitter); + d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release(); + if (d->vao->isCreated()) + d->vao->release(); +} + +/*! + Sets whether swizzling is enabled for the red and blue color channels to + \a swizzle. An BGRA to RGBA conversion (occurring in the shader on + the GPU, instead of a slow CPU-side transformation) can be useful + when the source texture contains data from a QImage with a format + like QImage::Format_ARGB32 which maps to BGRA on little endian + systems. + + By default the red-blue swizzle is disabled since this is what a + texture attached to an framebuffer object or a texture based on a + byte ordered QImage format (like QImage::Format_RGBA8888) needs. + */ +void QOpenGLTextureBlitter::setRedBlueSwizzle(bool swizzle) +{ + Q_D(QOpenGLTextureBlitter); + d->swizzle = swizzle; +} + +/*! + Changes the opacity to \a opacity. The default opacity is 1.0. + + \note the blitter does not alter the blend state. It is up to the + caller of blit() to ensure the correct blend settings are active. + + */ +void QOpenGLTextureBlitter::setOpacity(float opacity) +{ + Q_D(QOpenGLTextureBlitter); + d->opacity = opacity; +} + +/*! + \enum QOpenGLTextureBlitter::Origin + + \value OriginBottomLeft Indicates that the data in the texture + follows the OpenGL convention of coordinate systems, meaning Y is + running from bottom to top. + + \value OriginTopLeft Indicates that the data in the texture has Y + running from top to bottom, which is typical with regular, + unflipped image data. + + \sa blit() + */ + +/*! + Performs the blit with the source texture \a texture. + + \a targetTransform specifies the transformation applied. This is + usually generated by the targetTransform() helper function. + + \a sourceOrigin specifies if the image data needs flipping. When + \a texture corresponds to a texture attached to an FBO pass + OriginBottomLeft. On the other hand, when \a texture is based on + unflipped image data, pass OriginTopLeft. This is more efficient + than using QImage::mirrored(). + + \sa targetTransform(), Origin, bind() + */ +void QOpenGLTextureBlitter::blit(GLuint texture, + const QMatrix4x4 &targetTransform, + Origin sourceOrigin) +{ + Q_D(QOpenGLTextureBlitter); + d->blit(texture,targetTransform, sourceOrigin); +} + +/*! + Performs the blit with the source texture \a texture. + + \a targetTransform specifies the transformation applied. This is + usually generated by the targetTransform() helper function. + + \a sourceTransform specifies the transformation applied to the + source. This allows using only a sub-rect of the source + texture. This is usually generated by the sourceTransform() helper + function. + + \sa sourceTransform(), targetTransform(), Origin, bind() + */ +void QOpenGLTextureBlitter::blit(GLuint texture, + const QMatrix4x4 &targetTransform, + const QMatrix3x3 &sourceTransform) +{ + Q_D(QOpenGLTextureBlitter); + d->blit(texture, targetTransform, sourceTransform); +} + +/*! + Calculates a target transform suitable for blit(). + + \a target is the target rectangle in pixels. \a viewport describes + the source dimensions and will in most cases be set to (0, 0, + image width, image height). + + For unscaled output the size of \a target and \a viewport should + match. + + \sa blit() + */ +QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, + const QRect &viewport) +{ + qreal x_scale = target.width() / viewport.width(); + qreal y_scale = target.height() / viewport.height(); + + const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft(); + qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2); + qreal y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2); + + QMatrix4x4 matrix; + matrix(0,3) = x_translate; + matrix(1,3) = y_translate; + + matrix(0,0) = x_scale; + matrix(1,1) = y_scale; + + return matrix; +} + +/*! + Calculates a 3x3 matrix suitable as the input to blit(). This is + used when only a part of the texture is to be used in the blit. + + \a subTexture is the desired source rectangle in pixels, \a + textureSize is the full width and height of the texture data. \a + origin specifies the orientation of the image data when it comes + to the Y axis. + + \sa blit(), Origin + */ +QMatrix3x3 QOpenGLTextureBlitter::sourceTransform(const QRectF &subTexture, + const QSize &textureSize, + Origin origin) +{ + qreal x_scale = subTexture.width() / textureSize.width(); + qreal y_scale = subTexture.height() / textureSize.height(); + + const QPointF topLeft = subTexture.topLeft(); + qreal x_translate = topLeft.x() / textureSize.width(); + qreal y_translate = topLeft.y() / textureSize.height(); + + if (origin == OriginTopLeft) { + y_scale = -y_scale; + y_translate = 1 - y_translate; + } + + QMatrix3x3 matrix; + matrix(0,2) = x_translate; + matrix(1,2) = y_translate; + + matrix(0,0) = x_scale; + matrix(1,1) = y_scale; + + return matrix; +} + +QT_END_NAMESPACE diff --git a/src/opengl/qopengltextureblitter.h b/src/opengl/qopengltextureblitter.h new file mode 100644 index 0000000000..1818576085 --- /dev/null +++ b/src/opengl/qopengltextureblitter.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QOPENGLTEXTUREBLITTER_H +#define QOPENGLTEXTUREBLITTER_H + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGLTextureBlitterPrivate; + +class Q_OPENGL_EXPORT QOpenGLTextureBlitter +{ +public: + QOpenGLTextureBlitter(); + ~QOpenGLTextureBlitter(); + + enum Origin { + OriginBottomLeft, + OriginTopLeft + }; + + bool create(); + bool isCreated() const; + void destroy(); + + bool supportsExternalOESTarget() const; + + void bind(GLenum target = GL_TEXTURE_2D); + void release(); + + void setRedBlueSwizzle(bool swizzle); + void setOpacity(float opacity); + + void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin); + void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); + + static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport); + static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin); + +private: + Q_DISABLE_COPY(QOpenGLTextureBlitter) + Q_DECLARE_PRIVATE(QOpenGLTextureBlitter) + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif //QOPENGLTEXTUREBLITTER_H diff --git a/src/opengl/qopenglwindow.cpp b/src/opengl/qopenglwindow.cpp index 9328d9b46a..5da20dc559 100644 --- a/src/opengl/qopenglwindow.cpp +++ b/src/opengl/qopenglwindow.cpp @@ -40,12 +40,12 @@ #include "qopenglwindow.h" #include #include -#include #include #include #include #include #include +#include #include QT_BEGIN_NAMESPACE diff --git a/src/platformsupport/platformcompositor/platformcompositor.pro b/src/platformsupport/platformcompositor/platformcompositor.pro index c257d3e42c..89386ab3ef 100644 --- a/src/platformsupport/platformcompositor/platformcompositor.pro +++ b/src/platformsupport/platformcompositor/platformcompositor.pro @@ -1,7 +1,7 @@ TARGET = QtPlatformCompositorSupport MODULE = platformcompositor_support -QT = core-private gui-private +QT = core-private gui-private opengl CONFIG += static internal_module DEFINES += QT_NO_CAST_FROM_ASCII diff --git a/src/platformsupport/platformcompositor/qopenglcompositor_p.h b/src/platformsupport/platformcompositor/qopenglcompositor_p.h index 41a3288240..c9414c82c6 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor_p.h +++ b/src/platformsupport/platformcompositor/qopenglcompositor_p.h @@ -52,7 +52,7 @@ // #include -#include +#include #include QT_BEGIN_NAMESPACE diff --git a/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp b/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp index bcd2b90a87..ca50910114 100644 --- a/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp +++ b/src/platformsupport/platformcompositor/qplatformbackingstoreopenglsupport.cpp @@ -46,11 +46,10 @@ #include #include +#include #include #include #include -#include - #include #ifndef GL_TEXTURE_BASE_LEVEL diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index 6bf0d69770..74890ead82 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 6b59d87a0a..250d244c9f 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include @@ -43,7 +43,6 @@ class QWasmWindow; class QWasmScreen; class QOpenGLContext; class QOpenGLTexture; -class QOpenGLTextureBlitter; class QWasmCompositedWindow { diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp index 3a7ad6dad5..cf839e1931 100644 --- a/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3