Fix rendering of subpixel positioned native text
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
Tue, 5 Mar 2013 13:21:04 +0000 (14:21 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Thu, 7 Mar 2013 10:58:50 +0000 (11:58 +0100)
To get accurate sampling of the native text rendering, we use
nearest filtering. This, however, does not work well when we're
sampling in the middle of pixels and the result is that with
text which is positioned at 0.5 offsets, we will sample the
wrong pixels and get artifacts from this. The main use case
for native rendered text is unrotated and unscaled text,
so we fix this use case by pixel-aligning the translation
factor.

Done-with: Samuel

Task-number: QTBUG-30022
Change-Id: I6911196d6ff491dca3b329c42da1c6dd7263cff0
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>

src/quick/scenegraph/coreapi/qsgmaterial.cpp
src/quick/scenegraph/coreapi/qsgmaterial.h
src/quick/scenegraph/qsgdefaultglyphnode_p.cpp

index f678504..11ce987 100644 (file)
@@ -442,6 +442,16 @@ QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const
     return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix();
 }
 
+/*!
+    Returns the projection matrix.
+ */
+
+QMatrix4x4 QSGMaterialShader::RenderState::projectionMatrix() const
+{
+    Q_ASSERT(m_data);
+    return static_cast<const QSGRenderer *>(m_data)->currentProjectionMatrix();
+}
+
 
 
 /*!
index 50e9c77..238bf83 100644 (file)
@@ -69,6 +69,7 @@ public:
         float opacity() const;
         QMatrix4x4 combinedMatrix() const;
         QMatrix4x4 modelViewMatrix() const;
+        QMatrix4x4 projectionMatrix() const;
         QRect viewportRect() const;
         QRect deviceRect() const;
         float determinant() const;
index 6b8f992..b65686e 100644 (file)
@@ -178,7 +178,7 @@ void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial
                                                                1.0 / material->cacheTextureHeight()));
         glBindTexture(GL_TEXTURE_2D, material->texture()->textureId());
 
-        // Set the mag/min filters to be linear. We only need to do this when the texture
+        // Set the mag/min filters to be nearest. We only need to do this when the texture
         // has been recreated.
         if (updated) {
             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -186,8 +186,28 @@ void QSGTextMaskMaterialData::updateState(const RenderState &state, QSGMaterial
         }
     }
 
-    if (state.isMatrixDirty())
-        program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+    if (state.isMatrixDirty()) {
+        QMatrix4x4 transform = state.modelViewMatrix();
+        qreal xTranslation = transform(0, 3);
+        qreal yTranslation = transform(1, 3);
+
+        // Remove translation and check identity to see if matrix is only translating.
+        // If it is, we can round the translation to make sure the text is pixel aligned,
+        // which is the only thing that works with GL_NEAREST filtering. Adding rotations
+        // and scales to native rendered text is not a prioritized use case, since the
+        // default rendering type is designed for that.
+        transform(0, 3) = 0.0;
+        transform(1, 3) = 0.0;
+        if (transform.isIdentity()) {
+            transform(0, 3) = qRound(xTranslation);
+            transform(1, 3) = qRound(yTranslation);
+
+            transform = state.projectionMatrix() * transform;
+            program()->setUniformValue(m_matrix_id, transform);
+        } else {
+            program()->setUniformValue(m_matrix_id, state.combinedMatrix());
+        }
+    }
 }
 
 QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font)