aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp')
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp142
1 files changed, 131 insertions, 11 deletions
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 8a1a87cdc0..c5c4e18e37 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -48,6 +48,10 @@
#include <qopenglfunctions.h>
#include <qmath.h>
+#if !defined(QT_OPENGL_ES_2)
+#include <QtGui/qopenglfunctions_3_2_core.h>
+#endif
+
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlUseGlyphCacheWorkaround, QML_USE_GLYPHCACHE_WORKAROUND)
@@ -58,6 +62,9 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistance
, m_maxTextureCount(3)
, m_blitProgram(0)
, m_fboGuard(0)
+#if !defined(QT_OPENGL_ES_2)
+ , m_funcs(0)
+#endif
{
m_blitVertexCoordinateArray[0] = -1.0f;
m_blitVertexCoordinateArray[1] = -1.0f;
@@ -167,7 +174,7 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
if (glyph.width() != expectedWidth)
glyph = glyph.copy(0, 0, expectedWidth, glyph.height());
- if (useWorkaround()) {
+ if (useTextureResizeWorkaround()) {
uchar *inBits = glyph.scanLine(0);
uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x);
for (int y = 0; y < glyph.height(); ++y) {
@@ -177,7 +184,24 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
}
}
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+#if !defined(QT_OPENGL_ES_2)
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLenum format = GL_ALPHA;
+#endif
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < glyph.height(); ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y + i, glyph.width(),1,
+ format, GL_UNSIGNED_BYTE,
+ glyph.scanLine(i));
+ }
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y, glyph.width(), glyph.height(),
+ format, GL_UNSIGNED_BYTE,
+ glyph.constBits());
+ }
}
// restore to previous alignment
@@ -204,7 +228,7 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyph
void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height)
{
- if (useWorkaround() && texInfo->image.isNull())
+ if (useTextureResizeWorkaround() && texInfo->image.isNull())
texInfo->image = QDistanceField(width, height);
while (glGetError() != GL_NO_ERROR) { }
@@ -212,11 +236,20 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
glGenTextures(1, &texInfo->texture);
glBindTexture(GL_TEXTURE_2D, texInfo->texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+#if !defined(QT_OPENGL_ES_2)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLint internalFormat = GL_ALPHA;
+ const GLenum format = GL_ALPHA;
+#endif
+
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
texInfo->size = QSize(width, height);
@@ -236,6 +269,9 @@ static void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)
void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int width, int height)
{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ Q_ASSERT(ctx);
+
int oldWidth = texInfo->size.width();
int oldHeight = texInfo->size.height();
if (width == oldWidth && height == oldHeight)
@@ -249,12 +285,76 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
updateTexture(oldTexture, texInfo->texture, texInfo->size);
- if (useWorkaround()) {
+#if !defined(QT_OPENGL_ES_2)
+ if (isCoreProfile() && !useTextureResizeWorkaround()) {
+ // For an OpenGL Core Profile we can use http://www.opengl.org/wiki/Framebuffer#Blitting
+ // to efficiently copy the contents of the old texture to the new texture
+ // TODO: Use ARB_copy_image if available of if we have >=4.3 context
+ if (!m_funcs) {
+ m_funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>();
+ Q_ASSERT(m_funcs);
+ m_funcs->initializeOpenGLFunctions();
+ }
+
+ // Create a framebuffer object to which we can attach our old and new textures (to
+ // the first two color buffer attachment points)
+ if (!m_fboGuard) {
+ GLuint fbo;
+ m_funcs->glGenFramebuffers(1, &fbo);
+ m_fboGuard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
+ }
+
+ // Bind the FBO to both the GL_READ_FRAMEBUFFER? and GL_DRAW_FRAMEBUFFER targets
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
+
+ // Bind the old texture to GL_COLOR_ATTACHMENT0
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, oldTexture, 0);
+
+ // Bind the new texture to GL_COLOR_ATTACHMENT1
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
+ GL_TEXTURE_2D, texInfo->texture, 0);
+
+ // Set the source and destination buffers
+ m_funcs->glReadBuffer(GL_COLOR_ATTACHMENT0);
+ m_funcs->glDrawBuffer(GL_COLOR_ATTACHMENT1);
+
+ // Do the blit
+ m_funcs->glBlitFramebuffer(0, 0, oldWidth, oldHeight,
+ 0, 0, oldWidth, oldHeight,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // Reset the default framebuffer
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return;
+ } else if (useTextureResizeWorkaround()) {
+#else
+ if (useTextureResizeWorkaround()) {
+#endif
GLint alignment = 4; // default value
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.constBits());
+#if !defined(QT_OPENGL_ES_2)
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLenum format = GL_ALPHA;
+#endif
+
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < texInfo->image.height(); ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, i, oldWidth, 1,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.scanLine(i));
+ }
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, 0, oldWidth, oldHeight,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.constBits());
+ }
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value
@@ -278,12 +378,15 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
GLuint tmp_texture;
glGenTextures(1, &tmp_texture);
glBindTexture(GL_TEXTURE_2D, tmp_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+#if !defined(QT_OPENGL_ES_2)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tmp_texture, 0);
@@ -325,7 +428,12 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
glBindTexture(GL_TEXTURE_2D, texInfo->texture);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < oldHeight; ++i)
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, 0, i, oldWidth, 1);
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ }
ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
@@ -350,12 +458,12 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
m_blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
}
-bool QSGDefaultDistanceFieldGlyphCache::useWorkaround() const
+bool QSGDefaultDistanceFieldGlyphCache::useTextureResizeWorkaround() const
{
static bool set = false;
static bool useWorkaround = false;
if (!set) {
- QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(ctx));
+ QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(QOpenGLContext::currentContext()));
useWorkaround = ctx_p->workaround_brokenFBOReadBack
|| qmlUseGlyphCacheWorkaround(); // on some hardware the workaround is faster (see QTBUG-29264)
set = true;
@@ -363,6 +471,18 @@ bool QSGDefaultDistanceFieldGlyphCache::useWorkaround() const
return useWorkaround;
}
+bool QSGDefaultDistanceFieldGlyphCache::useTextureUploadWorkaround() const
+{
+ static bool set = false;
+ static bool useWorkaround = false;
+ if (!set) {
+ useWorkaround = qstrcmp(reinterpret_cast<const char*>(glGetString(GL_RENDERER)),
+ "Mali-400 MP") == 0;
+ set = true;
+ }
+ return useWorkaround;
+}
+
int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const
{
if (!m_maxTextureSize)