From dd3a08dd539a17e52bb8eec19c9aff27f4de7de4 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 28 Jul 2016 12:20:23 +0200 Subject: Make QOpenGLTextureBlitter public Change QOpenGLTextureBlitter to be a public API, as it was originally intended. There are now significant external uses outside qtbase (C++ compositor examples in QtWayland), and the API is considered proven enough. [ChangeLog][QtGui] QOpenGLTextureBlitter, a utility class to draw textured quads, has been made public. Change-Id: If7a2c94e1494195e2aa375d214932fa7b4c78321 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/kernel/qopenglwindow.cpp | 2 +- src/gui/opengl/opengl.pri | 2 +- src/gui/opengl/qopengltextureblitter.cpp | 193 ++++++++++++++++++++- src/gui/opengl/qopengltextureblitter.h | 94 ++++++++++ src/gui/opengl/qopengltextureblitter_p.h | 100 ----------- src/gui/painting/qplatformbackingstore.cpp | 6 +- .../platformcompositor/qopenglcompositor_p.h | 2 +- .../platforms/mirclient/qmirclientbackingstore.cpp | 4 +- tests/auto/gui/qopengl/tst_qopengl.cpp | 2 +- tests/manual/qopenglcontext/qopenglcontextwindow.h | 2 +- .../qopengltextureblitwindow.cpp | 4 +- .../qopengltextureblitwindow.h | 2 +- 12 files changed, 298 insertions(+), 115 deletions(-) create mode 100644 src/gui/opengl/qopengltextureblitter.h delete mode 100644 src/gui/opengl/qopengltextureblitter_p.h diff --git a/src/gui/kernel/qopenglwindow.cpp b/src/gui/kernel/qopenglwindow.cpp index 8ab5c08442..e1bd3d11b2 100644 --- a/src/gui/kernel/qopenglwindow.cpp +++ b/src/gui/kernel/qopenglwindow.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index b13f258fda..dfaf3042bc 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -32,7 +32,7 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2) { opengl/qopenglversionfunctionsfactory_p.h \ opengl/qopenglvertexarrayobject.h \ opengl/qopengldebug.h \ - opengl/qopengltextureblitter_p.h \ + opengl/qopengltextureblitter.h \ opengl/qopengltexture.h \ opengl/qopengltexture_p.h \ opengl/qopengltexturehelper_p.h \ diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp index 18ff0c4acf..2e74afcbc2 100644 --- a/src/gui/opengl/qopengltextureblitter.cpp +++ b/src/gui/opengl/qopengltextureblitter.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qopengltextureblitter_p.h" +#include "qopengltextureblitter.h" #include #include @@ -51,6 +51,49 @@ 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;" @@ -309,16 +352,44 @@ bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs 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(); @@ -358,12 +429,26 @@ bool QOpenGLTextureBlitter::create() 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()) @@ -376,12 +461,29 @@ void QOpenGLTextureBlitter::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); @@ -404,6 +506,11 @@ void QOpenGLTextureBlitter::bind(GLenum target) d->textureBuffer.release(); } +/*! + Unbinds the graphics resources used by the blitter. + + \sa bind() + */ void QOpenGLTextureBlitter::release() { Q_D(QOpenGLTextureBlitter); @@ -412,18 +519,64 @@ void QOpenGLTextureBlitter::release() d->vao->release(); } -void QOpenGLTextureBlitter::setSwizzleRB(bool swizzle) +/*! + Enables or disables swizzling for the red and blue color + channels. 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. 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) @@ -432,6 +585,19 @@ void QOpenGLTextureBlitter::blit(GLuint texture, 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) @@ -440,6 +606,18 @@ void QOpenGLTextureBlitter::blit(GLuint texture, 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 \viewport should + match. + + \sa blit() + */ QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, const QRect &viewport) { @@ -460,6 +638,17 @@ QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, 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) diff --git a/src/gui/opengl/qopengltextureblitter.h b/src/gui/opengl/qopengltextureblitter.h new file mode 100644 index 0000000000..2f7c6b1a0a --- /dev/null +++ b/src/gui/opengl/qopengltextureblitter.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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/gui/opengl/qopengltextureblitter_p.h b/src/gui/opengl/qopengltextureblitter_p.h deleted file mode 100644 index cc6499672d..0000000000 --- a/src/gui/opengl/qopengltextureblitter_p.h +++ /dev/null @@ -1,100 +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_P_H -#define QOPENGLTEXTUREBLITTER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#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 setSwizzleRB(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_P_H diff --git a/src/gui/painting/qplatformbackingstore.cpp b/src/gui/painting/qplatformbackingstore.cpp index d967a168d2..e2c5a82ffc 100644 --- a/src/gui/painting/qplatformbackingstore.cpp +++ b/src/gui/painting/qplatformbackingstore.cpp @@ -49,7 +49,7 @@ #include #include #ifndef QT_NO_OPENGL -#include +#include #endif #include #include @@ -389,7 +389,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i if (textureId) { if (d_ptr->needsSwizzle) - d_ptr->blitter->setSwizzleRB(true); + d_ptr->blitter->setRedBlueSwizzle(true); // The backingstore is for the entire tlw. // In case of native children offset tells the position relative to the tlw. const QRect srcRect = toBottomLeftRect(deviceWindowRect.translated(offset), d_ptr->textureSize.height()); @@ -398,7 +398,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion ®i origin); d_ptr->blitter->blit(textureId, QMatrix4x4(), source); if (d_ptr->needsSwizzle) - d_ptr->blitter->setSwizzleRB(false); + d_ptr->blitter->setRedBlueSwizzle(false); } // Textures for renderToTexture widgets that have WA_AlwaysStackOnTop set. diff --git a/src/platformsupport/platformcompositor/qopenglcompositor_p.h b/src/platformsupport/platformcompositor/qopenglcompositor_p.h index 2c34fba409..90651b807f 100644 --- a/src/platformsupport/platformcompositor/qopenglcompositor_p.h +++ b/src/platformsupport/platformcompositor/qopenglcompositor_p.h @@ -52,7 +52,7 @@ // #include -#include +#include QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp index f80d85842a..a4bb8864ab 100644 --- a/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp +++ b/src/plugins/platforms/mirclient/qmirclientbackingstore.cpp @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include QMirClientBackingStore::QMirClientBackingStore(QWindow* window) @@ -76,7 +76,7 @@ void QMirClientBackingStore::flush(QWindow* window, const QRegion& region, const mBlitter->create(); mBlitter->bind(); - mBlitter->setSwizzleRB(true); + mBlitter->setRedBlueSwizzle(true); mBlitter->blit(mTexture->textureId(), QMatrix4x4(), QOpenGLTextureBlitter::OriginTopLeft); mBlitter->release(); diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp index 15244744bf..ed48a4978a 100644 --- a/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/tests/manual/qopenglcontext/qopenglcontextwindow.h b/tests/manual/qopenglcontext/qopenglcontextwindow.h index f436d1af0e..37ff1b2082 100644 --- a/tests/manual/qopenglcontext/qopenglcontextwindow.h +++ b/tests/manual/qopenglcontext/qopenglcontextwindow.h @@ -31,9 +31,9 @@ #include #include +#include #include #include -#include class QOpenGLContextWindow : public QWindow { diff --git a/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp index 63ac1e4e66..f4e093a967 100644 --- a/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp +++ b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.cpp @@ -123,9 +123,9 @@ void QOpenGLTextureBlitWindow::render() m_blitter.blit(texture.textureId(), topRightOriginTopLeftVertex, topLeftOrigin); m_blitter.blit(texture_mirrored.textureId(), bottomLeftOriginTopLeftVertex, topLeftOrigin); - m_blitter.setSwizzleRB(true); + m_blitter.setRedBlueSwizzle(true); m_blitter.blit(texture.textureId(), bottomRightOriginTopLeftVertex, texTopLeftOriginTopLeft); - m_blitter.setSwizzleRB(false); + m_blitter.setRedBlueSwizzle(false); m_blitter.release(); if (m_blitter.supportsExternalOESTarget()) { diff --git a/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h index 957d833ef3..0912f096e4 100644 --- a/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h +++ b/tests/manual/qopengltextureblitter/qopengltextureblitwindow.h @@ -31,7 +31,7 @@ #include #include -#include +#include class QOpenGLTextureBlitWindow : public QWindow { -- cgit v1.2.3