Blame SOURCES/0010-Fix-distorted-text-with-subpixel-matrix-translation.patch

03bb49
From 55f07163f84badcc9aa0805f1523ef43a7225778 Mon Sep 17 00:00:00 2001
03bb49
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
03bb49
Date: Tue, 12 Oct 2021 13:13:01 +0200
03bb49
Subject: [PATCH 10/20] Fix distorted text with subpixel matrix translation
03bb49
03bb49
We would pixel-align native text *before* applying the
03bb49
model-view matrix, which would cause GL_NEAREST artifacts to
03bb49
show up when the text was positioned at a subpixel offset in
03bb49
some cases. Instead, we pixel-align the coordinates after mapping
03bb49
them to the view frustum, but before applying the projection to the
03bb49
screen.
03bb49
03bb49
To make it easier to modify the buffer layout for the shaders the
03bb49
next time, this also adds some constants for offsets.
03bb49
03bb49
[ChangeLog][Text] Fixed an issue where text using NativeRendering
03bb49
would look slightly skewed if it was inside a parent that had
03bb49
been positioned at a subpixel offset.
03bb49
03bb49
Pick-to: 5.15 6.2
03bb49
Fixes: QTBUG-96112
03bb49
Fixes: QTBUG-83626
03bb49
Task-number: QTBUG-55638
03bb49
Change-Id: Ifb785ad5830093df94afc75a7bc288e24ca7aa38
03bb49
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
03bb49
(cherry picked from commit b21948f5e811ce1b7abf065bc48af61a231e86f4)
03bb49
---
03bb49
 .../scenegraph/qsgdefaultglyphnode_p.cpp      | 46 ++++++----
03bb49
 .../scenegraph/shaders_ng/24bittextmask.frag  |  5 +-
03bb49
 .../scenegraph/shaders_ng/32bitcolortext.frag |  5 +-
03bb49
 .../scenegraph/shaders_ng/8bittextmask.frag   |  3 +-
03bb49
 .../scenegraph/shaders_ng/8bittextmask_a.frag |  3 +-
03bb49
 .../scenegraph/shaders_ng/outlinedtext.frag   |  5 +-
03bb49
 .../scenegraph/shaders_ng/outlinedtext.vert   |  9 +-
03bb49
 .../scenegraph/shaders_ng/outlinedtext_a.frag |  5 +-
03bb49
 .../scenegraph/shaders_ng/styledtext.frag     |  3 +-
03bb49
 .../scenegraph/shaders_ng/styledtext.vert     |  7 +-
03bb49
 .../scenegraph/shaders_ng/styledtext_a.frag   |  3 +-
03bb49
 src/quick/scenegraph/shaders_ng/textmask.frag |  3 +-
03bb49
 src/quick/scenegraph/shaders_ng/textmask.vert |  7 +-
03bb49
 ...text_nativerendering_subpixelpositions.qml | 91 +++++++++++++++++++
03bb49
 14 files changed, 155 insertions(+), 40 deletions(-)
03bb49
 create mode 100644 tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml
03bb49
03bb49
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
03bb49
index 3c60f830de..0fd6581dc4 100644
03bb49
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
03bb49
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
03bb49
@@ -428,6 +428,18 @@ QSGTextMaskRhiShader::QSGTextMaskRhiShader(QFontEngine::GlyphFormat glyphFormat)
03bb49
                       QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/textmask.frag.qsb"));
03bb49
 }
03bb49
 
03bb49
+enum UbufOffset {
03bb49
+    ModelViewMatrixOffset = 0,
03bb49
+    ProjectionMatrixOffset = ModelViewMatrixOffset + 64,
03bb49
+    ColorOffset = ProjectionMatrixOffset + 64,
03bb49
+    TextureScaleOffset = ColorOffset + 16,
03bb49
+    DprOffset = TextureScaleOffset + 8,
03bb49
+
03bb49
+    // + 1 float padding (vec4 must be aligned to 16)
03bb49
+    StyleColorOffset = DprOffset + 4 + 4,
03bb49
+    ShiftOffset = StyleColorOffset + 16
03bb49
+};
03bb49
+
03bb49
 bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
03bb49
                                              QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
03bb49
 {
03bb49
@@ -443,11 +455,14 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
03bb49
 
03bb49
     bool changed = false;
03bb49
     QByteArray *buf = state.uniformData();
03bb49
-    Q_ASSERT(buf->size() >= 92);
03bb49
+    Q_ASSERT(buf->size() >= DprOffset + 4);
03bb49
 
03bb49
     if (state.isMatrixDirty()) {
03bb49
-        const QMatrix4x4 m = state.combinedMatrix();
03bb49
-        memcpy(buf->data(), m.constData(), 64);
03bb49
+        const QMatrix4x4 mv = state.modelViewMatrix();
03bb49
+        memcpy(buf->data() + ModelViewMatrixOffset, mv.constData(), 64);
03bb49
+        const QMatrix4x4 p = state.projectionMatrix();
03bb49
+        memcpy(buf->data() + ProjectionMatrixOffset, p.constData(), 64);
03bb49
+
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
@@ -456,13 +471,13 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
03bb49
     if (updated || !oldMat || oldRtex != newRtex) {
03bb49
         const QVector2D textureScale = QVector2D(1.0f / mat->rhiGlyphCache()->width(),
03bb49
                                                  1.0f / mat->rhiGlyphCache()->height());
03bb49
-        memcpy(buf->data() + 64 + 16, &textureScale, 8);
03bb49
+        memcpy(buf->data() + TextureScaleOffset, &textureScale, 8);
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
     if (!oldMat) {
03bb49
         float dpr = state.devicePixelRatio();
03bb49
-        memcpy(buf->data() + 64 + 16 + 8, &dpr, 4);
03bb49
+        memcpy(buf->data() + DprOffset, &dpr, 4);
03bb49
     }
03bb49
 
03bb49
     // move texture uploads/copies onto the renderer's soon-to-be-committed list
03bb49
@@ -510,11 +525,11 @@ bool QSG8BitTextMaskRhiShader::updateUniformData(RenderState &state,
03bb49
     QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
03bb49
 
03bb49
     QByteArray *buf = state.uniformData();
03bb49
-    Q_ASSERT(buf->size() >= 80);
03bb49
+    Q_ASSERT(buf->size() >= ColorOffset + 16);
03bb49
 
03bb49
     if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
03bb49
         const QVector4D color = qsg_premultiply(mat->color(), state.opacity());
03bb49
-        memcpy(buf->data() + 64, &color, 16);
03bb49
+        memcpy(buf->data() + ColorOffset, &color, 16);
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
@@ -553,12 +568,12 @@ bool QSG24BitTextMaskRhiShader::updateUniformData(RenderState &state,
03bb49
     QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
03bb49
 
03bb49
     QByteArray *buf = state.uniformData();
03bb49
-    Q_ASSERT(buf->size() >= 92);
03bb49
+    Q_ASSERT(buf->size() >= ColorOffset + 16);
03bb49
 
03bb49
     if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
03bb49
         // shader takes vec4 but uses alpha only; coloring happens via the blend constant
03bb49
         const QVector4D color = qsg_premultiply(mat->color(), state.opacity());
03bb49
-        memcpy(buf->data() + 64, &color, 16);
03bb49
+        memcpy(buf->data() + ColorOffset, &color, 16);
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
@@ -608,12 +623,12 @@ bool QSG32BitColorTextRhiShader::updateUniformData(RenderState &state,
03bb49
     QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
03bb49
 
03bb49
     QByteArray *buf = state.uniformData();
03bb49
-    Q_ASSERT(buf->size() >= 92);
03bb49
+    Q_ASSERT(buf->size() >= ColorOffset + 16);
03bb49
 
03bb49
     if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
03bb49
         // shader takes vec4 but uses alpha only
03bb49
         const QVector4D color(0, 0, 0, mat->color().w() * state.opacity());
03bb49
-        memcpy(buf->data() + 64, &color, 16);
03bb49
+        memcpy(buf->data() + ColorOffset, &color, 16);
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
@@ -649,20 +664,17 @@ bool QSGStyledTextRhiShader::updateUniformData(RenderState &state,
03bb49
     QSGStyledTextMaterial *oldMat = static_cast<QSGStyledTextMaterial *>(oldMaterial);
03bb49
 
03bb49
     QByteArray *buf = state.uniformData();
03bb49
-    Q_ASSERT(buf->size() >= 120);
03bb49
-
03bb49
-    // matrix..dpr + 1 float padding (vec4 must be aligned to 16)
03bb49
-    const int startOffset = 64 + 16 + 8 + 4 + 4;
03bb49
+    Q_ASSERT(buf->size() >= ShiftOffset + 8);
03bb49
 
03bb49
     if (oldMat == nullptr || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) {
03bb49
         const QVector4D styleColor = qsg_premultiply(mat->styleColor(), state.opacity());
03bb49
-        memcpy(buf->data() + startOffset, &styleColor, 16);
03bb49
+        memcpy(buf->data() + StyleColorOffset, &styleColor, 16);
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
     if (oldMat == nullptr || oldMat->styleShift() != mat->styleShift()) {
03bb49
         const QVector2D v = mat->styleShift();
03bb49
-        memcpy(buf->data() + startOffset + 16, &v, 8);
03bb49
+        memcpy(buf->data() + ShiftOffset, &v, 8);
03bb49
         changed = true;
03bb49
     }
03bb49
 
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag b/src/quick/scenegraph/shaders_ng/24bittextmask.frag
03bb49
index bc3826a924..ed8da4cd30 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag
03bb49
@@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
-    vec4 color; // only alpha is used, but must be vec4 due to layout compat
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
+    vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
 } ubuf;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
03bb49
index 63e445f90b..4198a4d339 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
03bb49
@@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
-    vec4 color; // only alpha is used, but must be vec4 due to layout compat
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
+    vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
 } ubuf;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag b/src/quick/scenegraph/shaders_ng/8bittextmask.frag
03bb49
index 6304e821ff..a06743876d 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag
03bb49
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
03bb49
index 0d0fa1cd3a..f725cbc5e7 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
03bb49
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag b/src/quick/scenegraph/shaders_ng/outlinedtext.frag
03bb49
index 947d161a50..e2f82d3845 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag
03bb49
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    // must match styledtext
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
+    // the above must stay compatible with textmask/8bittextmask
03bb49
     vec4 styleColor;
03bb49
     vec2 shift;
03bb49
 } ubuf;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert b/src/quick/scenegraph/shaders_ng/outlinedtext.vert
03bb49
index 023f9dfdc2..4068e42f28 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert
03bb49
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert
03bb49
@@ -10,11 +10,12 @@ layout(location = 3) out vec2 sCoordLeft;
03bb49
 layout(location = 4) out vec2 sCoordRight;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    // must match styledtext
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
+    // the above must stay compatible with textmask/8bittextmask
03bb49
     vec4 styleColor;
03bb49
     vec2 shift;
03bb49
 } ubuf;
03bb49
@@ -28,6 +29,6 @@ void main()
03bb49
      sCoordDown = (tCoord - vec2(0.0, 1.0)) * ubuf.textureScale;
03bb49
      sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * ubuf.textureScale;
03bb49
      sCoordRight = (tCoord - vec2(1.0, 0.0)) * ubuf.textureScale;
03bb49
-     vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
03bb49
-     gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
03bb49
+     vec4 xformed = ubuf.modelViewMatrix * vCoord;
03bb49
+     gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
03bb49
 }
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
03bb49
index 5b7bd9ca82..274d891a3c 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
03bb49
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    // must match styledtext
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
+    // the above must stay compatible with textmask/8bittextmask
03bb49
     vec4 styleColor;
03bb49
     vec2 shift;
03bb49
 } ubuf;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag b/src/quick/scenegraph/shaders_ng/styledtext.frag
03bb49
index 0b16396037..2e380dfeae 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag
03bb49
@@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert b/src/quick/scenegraph/shaders_ng/styledtext.vert
03bb49
index beadf07c79..271dae8d8a 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert
03bb49
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert
03bb49
@@ -7,7 +7,8 @@ layout(location = 0) out vec2 sampleCoord;
03bb49
 layout(location = 1) out vec2 shiftedSampleCoord;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
@@ -22,6 +23,6 @@ void main()
03bb49
 {
03bb49
      sampleCoord = tCoord * ubuf.textureScale;
03bb49
      shiftedSampleCoord = (tCoord - ubuf.shift) * ubuf.textureScale;
03bb49
-     vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
03bb49
-     gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
03bb49
+     vec4 xformed = ubuf.modelViewMatrix * vCoord;
03bb49
+     gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
03bb49
 }
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag b/src/quick/scenegraph/shaders_ng/styledtext_a.frag
03bb49
index b673137895..62e162c851 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag
03bb49
@@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag b/src/quick/scenegraph/shaders_ng/textmask.frag
03bb49
index 518d5c965f..ed8da4cd30 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/textmask.frag
03bb49
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag
03bb49
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
03bb49
 layout(binding = 1) uniform sampler2D _qt_texture;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert b/src/quick/scenegraph/shaders_ng/textmask.vert
03bb49
index 9d80d5dadb..e0b3c01bce 100644
03bb49
--- a/src/quick/scenegraph/shaders_ng/textmask.vert
03bb49
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert
03bb49
@@ -6,7 +6,8 @@ layout(location = 1) in vec2 tCoord;
03bb49
 layout(location = 0) out vec2 sampleCoord;
03bb49
 
03bb49
 layout(std140, binding = 0) uniform buf {
03bb49
-    mat4 matrix;
03bb49
+    mat4 modelViewMatrix;
03bb49
+    mat4 projectionMatrix;
03bb49
     vec4 color;
03bb49
     vec2 textureScale;
03bb49
     float dpr;
03bb49
@@ -17,6 +18,6 @@ out gl_PerVertex { vec4 gl_Position; };
03bb49
 void main()
03bb49
 {
03bb49
      sampleCoord = tCoord * ubuf.textureScale;
03bb49
-     vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
03bb49
-     gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
03bb49
+     vec4 xformed = ubuf.modelViewMatrix * vCoord;
03bb49
+     gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
03bb49
 }
03bb49
diff --git a/tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml b/tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml
03bb49
new file mode 100644
03bb49
index 0000000000..c60fc4d8b0
03bb49
--- /dev/null
03bb49
+++ b/tests/manual/scenegraph_lancelot/data/text/text_nativerendering_subpixelpositions.qml
03bb49
@@ -0,0 +1,91 @@
03bb49
+import QtQuick 2.0
03bb49
+
03bb49
+//vary font style, native rendering at non-integer offsets
03bb49
+
03bb49
+Item {
03bb49
+    id: topLevel
03bb49
+    width: 320
03bb49
+    height: 580
03bb49
+
03bb49
+    Repeater {
03bb49
+        model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken]
03bb49
+        Text {
03bb49
+            y: 20 * index
03bb49
+            clip: true
03bb49
+            renderType: Text.NativeRendering
03bb49
+            width: parent.width
03bb49
+            wrapMode: Text.Wrap
03bb49
+            font.pointSize: 10
03bb49
+            style: modelData
03bb49
+            styleColor: "green"
03bb49
+            text: "The quick fox jumps in style " + modelData
03bb49
+        }
03bb49
+    }
03bb49
+
03bb49
+    Repeater {
03bb49
+        model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken]
03bb49
+        Text {
03bb49
+            y: 100.5 + 20 * index
03bb49
+            clip: true
03bb49
+            renderType: Text.NativeRendering
03bb49
+            width: parent.width
03bb49
+            wrapMode: Text.Wrap
03bb49
+            font.pointSize: 10
03bb49
+            style: modelData
03bb49
+            styleColor: "green"
03bb49
+            text: "The quick fox jumps in style " + modelData
03bb49
+        }
03bb49
+    }
03bb49
+
03bb49
+    Repeater {
03bb49
+        model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken]
03bb49
+        Text {
03bb49
+            y: 200.5 + 20 * index
03bb49
+            x: 0.5
03bb49
+            clip: true
03bb49
+            renderType: Text.NativeRendering
03bb49
+            width: parent.width
03bb49
+            wrapMode: Text.Wrap
03bb49
+            font.pointSize: 10
03bb49
+            style: modelData
03bb49
+            styleColor: "green"
03bb49
+            text: "The quick fox jumps in style " + modelData
03bb49
+        }
03bb49
+    }
03bb49
+
03bb49
+    Repeater {
03bb49
+        model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken]
03bb49
+        Text {
03bb49
+            y: 300.5 + 20 * index
03bb49
+            x: 0.5
03bb49
+            clip: true
03bb49
+            renderType: Text.NativeRendering
03bb49
+            width: parent.width
03bb49
+            wrapMode: Text.Wrap
03bb49
+            font.pointSize: 10
03bb49
+            style: modelData
03bb49
+            styleColor: "green"
03bb49
+            text: "The quick fox jumps in style " + modelData
03bb49
+        }
03bb49
+    }
03bb49
+
03bb49
+    Repeater {
03bb49
+        model: [Text.Normal, Text.Outline, Text.Raised, Text.Sunken]
03bb49
+        Rectangle {
03bb49
+            y: 400.5 + 20 * index
03bb49
+            x: 0.5
03bb49
+            width: topLevel.width
03bb49
+            height: topLevel.height
03bb49
+            clip: true
03bb49
+            Text {
03bb49
+                renderType: Text.NativeRendering
03bb49
+                width: parent.width
03bb49
+                wrapMode: Text.Wrap
03bb49
+                font.pointSize: 10
03bb49
+                style: modelData
03bb49
+                styleColor: "green"
03bb49
+                text: "The quick fox jumps in style " + modelData
03bb49
+            }
03bb49
+        }
03bb49
+    }
03bb49
+}
03bb49
-- 
03bb49
2.35.1
03bb49