summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/opengl/qopengltextureblitter.cpp125
-rw-r--r--src/opengl/qopengltextureblitter.h1
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 <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();
@@ -477,13 +544,39 @@ bool QOpenGLTextureBlitter::supportsExternalOESTarget() const
}
/*!
+ \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
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.
+ 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();