From 60d9509cb00526e8530926b19b2366e584fdf30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Sat, 27 Nov 2021 18:51:03 +0100 Subject: Teach QOpenGLTextureBlitter about GL_TEXTURE_RECTANGLE textures Change-Id: Ie577bda046f60ce23dfb8cdd6164bb3de4b54358 Reviewed-by: Laszlo Agocs --- src/opengl/qopengltextureblitter.cpp | 125 ++++++++++++++++++++++++++++++----- src/opengl/qopengltextureblitter.h | 1 + 2 files changed, 110 insertions(+), 16 deletions(-) diff --git a/src/opengl/qopengltextureblitter.cpp b/src/opengl/qopengltextureblitter.cpp index 0f389547cc..292b08a0a6 100644 --- a/src/opengl/qopengltextureblitter.cpp +++ b/src/opengl/qopengltextureblitter.cpp @@ -44,10 +44,20 @@ #include #include #include +#include #ifndef GL_TEXTURE_EXTERNAL_OES #define GL_TEXTURE_EXTERNAL_OES 0x8D65 #endif +#ifndef GL_TEXTURE_RECTANGLE +#define GL_TEXTURE_RECTANGLE 0x84F5 +#endif +#ifndef GL_TEXTURE_WIDTH +#define GL_TEXTURE_WIDTH 0x1000 +#endif +#ifndef GL_TEXTURE_HEIGHT +#define GL_TEXTURE_HEIGHT 0x1001 +#endif QT_BEGIN_NAMESPACE @@ -153,6 +163,30 @@ static const char fragment_shader_external_oes[] = " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" "}"; +static const char fragment_shader_rectangle[] = + "varying highp vec2 uv;" + "uniform sampler2DRect textureSampler;" + "uniform bool swizzle;" + "uniform highp float opacity;" + "void main() {" + " highp vec4 tmpFragColor = texture2DRect(textureSampler,uv);" + " tmpFragColor.a *= opacity;" + " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" + "}"; + +static const char fragment_shader150_rectangle[] = + "#version 150 core\n" + "in vec2 uv;" + "out vec4 fragcolor;" + "uniform sampler2DRect textureSampler;" + "uniform bool swizzle;" + "uniform float opacity;" + "void main() {" + " vec4 tmpFragColor = texture(textureSampler, uv);" + " tmpFragColor.a *= opacity;" + " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;" + "}"; + static const GLfloat vertex_buffer_data[] = { -1,-1, 0, -1, 1, 0, @@ -198,7 +232,8 @@ public: enum ProgramIndex { TEXTURE_2D, - TEXTURE_EXTERNAL_OES + TEXTURE_EXTERNAL_OES, + TEXTURE_RECTANGLE }; QOpenGLTextureBlitterPrivate() : @@ -210,8 +245,10 @@ public: 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 blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); + void blit(GLuint texture, const QMatrix4x4 &targetTransform, QOpenGLTextureBlitter::Origin origin); + + QMatrix3x3 toTextureCoordinates(const QMatrix3x3 &sourceTransform) const; void prepareProgram(const QMatrix4x4 &vertexTransform); @@ -239,7 +276,7 @@ public: bool swizzle; float opacity; TextureMatrixUniform textureMatrixUniformState; - } programs[2]; + } programs[3]; bool swizzle; float opacity; QScopedPointer vao; @@ -253,6 +290,8 @@ static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GL return QOpenGLTextureBlitterPrivate::TEXTURE_2D; case GL_TEXTURE_EXTERNAL_OES: return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES; + case GL_TEXTURE_RECTANGLE: + return QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE; default: qWarning("Unsupported texture target 0x%x", target); return QOpenGLTextureBlitterPrivate::TEXTURE_2D; @@ -286,14 +325,33 @@ void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransf } } +QMatrix3x3 QOpenGLTextureBlitterPrivate::toTextureCoordinates(const QMatrix3x3 &sourceTransform) const +{ + if (currentTarget == GL_TEXTURE_RECTANGLE) { + // Non-normalized coordinates + QMatrix4x4 textureTransform(sourceTransform); + if (auto *glFunctions = QOpenGLContext::currentContext()->extraFunctions()) { + int width, height; + glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_WIDTH, &width); + glFunctions->glGetTexLevelParameteriv(currentTarget, 0, GL_TEXTURE_HEIGHT, &height); + textureTransform.scale(width, height); + } + return textureTransform.toGenericMatrix<3, 3>(); + } + + return sourceTransform; // Normalized coordinates +} + void QOpenGLTextureBlitterPrivate::blit(GLuint texture, - const QMatrix4x4 &vertexTransform, - const QMatrix3x3 &textureTransform) + const QMatrix4x4 &targetTransform, + const QMatrix3x3 &sourceTransform) { TextureBinder binder(currentTarget, texture); - prepareProgram(vertexTransform); + prepareProgram(targetTransform); Program *program = &programs[targetToProgramIndex(currentTarget)]; + + const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform); program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform); program->textureMatrixUniformState = User; @@ -301,26 +359,28 @@ void QOpenGLTextureBlitterPrivate::blit(GLuint texture, } void QOpenGLTextureBlitterPrivate::blit(GLuint texture, - const QMatrix4x4 &vertexTransform, + const QMatrix4x4 &targetTransform, QOpenGLTextureBlitter::Origin origin) { TextureBinder binder(currentTarget, texture); - prepareProgram(vertexTransform); + prepareProgram(targetTransform); Program *program = &programs[targetToProgramIndex(currentTarget)]; + + QMatrix3x3 sourceTransform; if (origin == QOpenGLTextureBlitter::OriginTopLeft) { if (program->textureMatrixUniformState != IdentityFlipped) { - QMatrix3x3 flipped; - flipped(1,1) = -1; - flipped(1,2) = 1; - program->glProgram->setUniformValue(program->textureTransformUniformPos, flipped); + sourceTransform(1,1) = -1; + sourceTransform(1,2) = 1; program->textureMatrixUniformState = IdentityFlipped; } } else if (program->textureMatrixUniformState != Identity) { - program->glProgram->setUniformValue(program->textureTransformUniformPos, QMatrix3x3()); program->textureMatrixUniformState = Identity; } + const QMatrix3x3 textureTransform = toTextureCoordinates(sourceTransform); + program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform); + QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); } @@ -408,12 +468,18 @@ bool QOpenGLTextureBlitter::create() if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150)) return false; + if (supportsRectangleTarget()) + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE, vertex_shader150, fragment_shader150_rectangle)) + 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; + if (supportsRectangleTarget()) + if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE, vertex_shader, fragment_shader_rectangle)) + return false; } // Create and bind the VAO, if supported. @@ -459,6 +525,7 @@ void QOpenGLTextureBlitter::destroy() Q_D(QOpenGLTextureBlitter); d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset(); d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset(); + d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_RECTANGLE].glProgram.reset(); d->vertexBuffer.destroy(); d->textureBuffer.destroy(); d->vao.reset(); @@ -476,6 +543,32 @@ bool QOpenGLTextureBlitter::supportsExternalOESTarget() const return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external"); } +/*! + \return \c true when bind() accepts \c GL_TEXTURE_RECTANGLE as + its target argument. + + \sa bind(), blit() + */ +bool QOpenGLTextureBlitter::supportsRectangleTarget() const +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx || ctx->isOpenGLES()) + return false; + + if (ctx->hasExtension("GL_ARB_texture_rectangle")) + return true; + + if (ctx->hasExtension("GL_EXT_texture_rectangle")) + return true; + + QSurfaceFormat f = ctx->format(); + const auto version = qMakePair(f.majorVersion(), f.minorVersion()); + if (version >= qMakePair(3, 1)) + return true; + + return false; +} + /*! Binds the graphics resources used by the blitter. This must be called before calling blit(). Code modifying the OpenGL state @@ -483,7 +576,7 @@ bool QOpenGLTextureBlitter::supportsExternalOESTarget() const 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. + either \c GL_TEXTURE_2D, \c GL_TEXTURE_RECTANGLE, or \c GL_OES_EGL_image_external. \sa release(), blit() */ @@ -586,7 +679,7 @@ void QOpenGLTextureBlitter::blit(GLuint texture, Origin sourceOrigin) { Q_D(QOpenGLTextureBlitter); - d->blit(texture,targetTransform, sourceOrigin); + d->blit(texture, targetTransform, sourceOrigin); } /*! diff --git a/src/opengl/qopengltextureblitter.h b/src/opengl/qopengltextureblitter.h index 1818576085..1f204ee160 100644 --- a/src/opengl/qopengltextureblitter.h +++ b/src/opengl/qopengltextureblitter.h @@ -66,6 +66,7 @@ public: void destroy(); bool supportsExternalOESTarget() const; + bool supportsRectangleTarget() const; void bind(GLenum target = GL_TEXTURE_2D); void release(); -- cgit v1.2.3