Teach QOpenGLTextureBlitter about GL_TEXTURE_RECTANGLE textures

Change-Id: Ie577bda046f60ce23dfb8cdd6164bb3de4b54358
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
bb10
Tor Arne Vestbø 2021-11-27 18:51:03 +01:00
parent 0fa98a26fd
commit 60d9509cb0
2 changed files with 110 additions and 16 deletions

View File

@ -44,10 +44,20 @@
#include <QtOpenGL/QOpenGLBuffer>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLExtraFunctions>
#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<QOpenGLVertexArrayObject> 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);
}
/*!

View File

@ -66,6 +66,7 @@ public:
void destroy();
bool supportsExternalOESTarget() const;
bool supportsRectangleTarget() const;
void bind(GLenum target = GL_TEXTURE_2D);
void release();