Revision control
++ // Copyright (C) 2019 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #include "qsgdistancefieldglyphnode_p_p.h"
++ #include "qsgrhidistancefieldglyphcache_p.h"
++ #include <QtGui/qsurface.h>
++ #include <QtGui/qwindow.h>
++ #include <qmath.h>
++
++ QT_BEGIN_NAMESPACE
++
++ static float qt_sg_envFloat(const char *name, float defaultValue)
++ {
++ if (Q_LIKELY(!qEnvironmentVariableIsSet(name)))
++ return defaultValue;
++ bool ok = false;
++ const float value = qgetenv(name).toFloat(&ok);
++ return ok ? value : defaultValue;
++ }
++
++ static float thresholdFunc(float glyphScale)
++ {
++ static const float base = qt_sg_envFloat("QT_DF_BASE", 0.5f);
++ static const float baseDev = qt_sg_envFloat("QT_DF_BASEDEVIATION", 0.065f);
++ static const float devScaleMin = qt_sg_envFloat("QT_DF_SCALEFORMAXDEV", 0.15f);
++ static const float devScaleMax = qt_sg_envFloat("QT_DF_SCALEFORNODEV", 0.3f);
++ return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev);
++ }
++
++ static float spreadFunc(float glyphScale)
++ {
++ static const float range = qt_sg_envFloat("QT_DF_RANGE", 0.06f);
++ return range / glyphScale;
++ }
++
++ class QSGDistanceFieldTextMaterialRhiShader : public QSGMaterialShader
++ {
++ public:
++ QSGDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount);
++
++ bool updateUniformData(RenderState &state,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++
++ void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++
++ protected:
++ float m_fontScale = 1.0;
++ float m_matrixScale = 1.0;
++ quint32 m_currentUbufOffset;
++ };
++
++ QSGDistanceFieldTextMaterialRhiShader::QSGDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext.frag.qsb"), viewCount);
++ }
++
++ bool QSGDistanceFieldTextMaterialRhiShader::updateUniformData(RenderState &state,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
++ {
++ Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
++ QSGDistanceFieldTextMaterial *mat = static_cast<QSGDistanceFieldTextMaterial *>(newMaterial);
++ QSGDistanceFieldTextMaterial *oldMat = static_cast<QSGDistanceFieldTextMaterial *>(oldMaterial);
++
++ // updateUniformData() is called before updateSampledImage() by the
++ // renderer. Hence updating the glyph cache stuff here.
++ const bool textureUpdated = mat->updateTextureSizeAndWrapper();
++ Q_ASSERT(mat->wrapperTexture());
++ Q_ASSERT(oldMat == nullptr || oldMat->texture());
++
++ bool changed = false;
++ QByteArray *buf = state.uniformData();
++ Q_ASSERT(buf->size() >= 104);
++
++ bool updateRange = false;
++ if (!oldMat || mat->fontScale() != oldMat->fontScale()) {
++ m_fontScale = mat->fontScale();
++ updateRange = true;
++ }
++ if (state.isMatrixDirty()) {
++ m_matrixScale = qSqrt(qAbs(state.determinant())) * state.devicePixelRatio();
++ updateRange = true;
++ }
++ quint32 offset = 0;
++ const int matrixCount = qMin(state.projectionMatrixCount(), newMaterial->viewCount());
++ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
++ if (state.isMatrixDirty()) {
++ const QMatrix4x4 m = state.combinedMatrix(viewIndex);
++ memcpy(buf->data() + 64 * viewIndex, m.constData(), 64);
++ changed = true;
++ }
++ offset += 64;
++ }
++ if (textureUpdated || !oldMat || oldMat->texture()->texture != mat->texture()->texture) {
++ const QVector2D ts(1.0f / mat->textureSize().width(), 1.0f / mat->textureSize().height());
++ Q_ASSERT(sizeof(ts) == 8);
++ memcpy(buf->data() + offset, &ts, 8);
++ changed = true;
++ }
++ offset += 8 + 8; // 8 is padding for vec4 alignment
++ if (!oldMat || mat->color() != oldMat->color() || state.isOpacityDirty()) {
++ const QVector4D color = mat->color() * state.opacity();
++ Q_ASSERT(sizeof(color) == 16);
++ memcpy(buf->data() + offset, &color, 16);
++ changed = true;
++ }
++ offset += 16;
++ if (updateRange) { // deferred because depends on m_fontScale and m_matrixScale
++ const float combinedScale = m_fontScale * m_matrixScale;
++ const float base = thresholdFunc(combinedScale);
++ const float range = spreadFunc(combinedScale);
++ const QVector2D alphaMinMax(qMax(0.0f, base - range), qMin(base + range, 1.0f));
++ memcpy(buf->data() + offset, &alphaMinMax, 8);
++ changed = true;
++ }
++ offset += 8; // not adding any padding here since we are not sure what comes afterwards in the subclasses' shaders
++
++ // move texture uploads/copies onto the renderer's soon-to-be-committed list
++ static_cast<QSGRhiDistanceFieldGlyphCache *>(mat->glyphCache())->commitResourceUpdates(state.resourceUpdateBatch());
++
++ m_currentUbufOffset = offset;
++ return changed;
++ }
++
++ void QSGDistanceFieldTextMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
++ QSGMaterial *newMaterial, QSGMaterial *)
++ {
++ Q_UNUSED(state);
++ if (binding != 1)
++ return;
++
++ QSGDistanceFieldTextMaterial *mat = static_cast<QSGDistanceFieldTextMaterial *>(newMaterial);
++ QSGTexture *t = mat->wrapperTexture();
++ t->setFiltering(QSGTexture::Linear);
++ *texture = t;
++ }
++
++ class DistanceFieldAnisotropicTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader
++ {
++ public:
++ DistanceFieldAnisotropicTextMaterialRhiShader(bool alphaTexture, int viewCount);
++ };
++
++ DistanceFieldAnisotropicTextMaterialRhiShader::DistanceFieldAnisotropicTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext_a_fwidth.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext_fwidth.frag.qsb"), viewCount);
++ }
++
++ QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial()
++ : m_glyph_cache(nullptr)
++ , m_texture(nullptr)
++ , m_fontScale(1.0)
++ , m_sgTexture(nullptr)
++ {
++ setFlag(Blending | RequiresDeterminant, true);
++ }
++
++ QSGDistanceFieldTextMaterial::~QSGDistanceFieldTextMaterial()
++ {
++ delete m_sgTexture;
++ }
++
++ QSGMaterialType *QSGDistanceFieldTextMaterial::type() const
++ {
++ static QSGMaterialType type;
++ return &type;
++ }
++
++ void QSGDistanceFieldTextMaterial::setColor(const QColor &color)
++ {
++ float r, g, b, a;
++ color.getRgbF(&r, &g, &b, &a);
++ m_color = QVector4D(r * a, g * a, b * a, a);
++ }
++
++ QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
++ {
++ if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported())
++ return new DistanceFieldAnisotropicTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ else
++ return new QSGDistanceFieldTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ }
++
++ bool QSGDistanceFieldTextMaterial::updateTextureSize()
++ {
++ if (!m_texture)
++ m_texture = m_glyph_cache->glyphTexture(0); // invalid texture
++
++ if (m_texture->size != m_size) {
++ m_size = m_texture->size;
++ return true;
++ }
++
++ return false;
++ }
++
++ // When using the RHI we need a QSGTexture wrapping the QRhiTexture, just
++ // exposing a QRhiTexture * (which would be the equivalent of GLuint textureId)
++ // is not sufficient to play nice with the material.
++ bool QSGDistanceFieldTextMaterial::updateTextureSizeAndWrapper()
++ {
++ bool updated = updateTextureSize();
++ if (updated) {
++ if (m_sgTexture)
++ delete m_sgTexture;
++ m_sgTexture = new QSGPlainTexture;
++ m_sgTexture->setTexture(m_texture->texture);
++ m_sgTexture->setTextureSize(m_size);
++ m_sgTexture->setOwnsTexture(false);
++ }
++ return updated;
++ }
++
++ int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const
++ {
++ Q_ASSERT(o && type() == o->type());
++ const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o);
++ if (m_glyph_cache != other->m_glyph_cache)
++ return m_glyph_cache - other->m_glyph_cache;
++ if (m_fontScale != other->m_fontScale) {
++ return int(other->m_fontScale < m_fontScale) - int(m_fontScale < other->m_fontScale);
++ }
++ if (m_color != other->m_color)
++ return &m_color < &other->m_color ? -1 : 1;
++ qintptr t0 = m_texture ? qintptr(m_texture->texture) : 0;
++ qintptr t1 = other->m_texture ? qintptr(other->m_texture->texture) : 0;
++ const qintptr diff = t0 - t1;
++ return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
++ }
++ class DistanceFieldStyledTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader
++ {
++ public:
++ DistanceFieldStyledTextMaterialRhiShader(bool alphaTexture, int viewCount);
++
++ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++ };
++
++ DistanceFieldStyledTextMaterialRhiShader::DistanceFieldStyledTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ }
++
++ bool DistanceFieldStyledTextMaterialRhiShader::updateUniformData(RenderState &state,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
++ {
++ bool changed = QSGDistanceFieldTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
++ QSGDistanceFieldStyledTextMaterial *mat = static_cast<QSGDistanceFieldStyledTextMaterial *>(newMaterial);
++ QSGDistanceFieldStyledTextMaterial *oldMat = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldMaterial);
++
++ QByteArray *buf = state.uniformData();
++ Q_ASSERT(buf->size() >= 128);
++
++ // must add 8 bytes padding for vec4 alignment, the base class did not do this
++ m_currentUbufOffset += 8; // now at StyleColor
++
++ if (!oldMat || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) {
++ QVector4D styleColor = mat->styleColor();
++ styleColor *= state.opacity();
++
++ memcpy(buf->data() + m_currentUbufOffset, &styleColor, 16);
++ changed = true;
++ }
++ m_currentUbufOffset += 16;
++
++ return changed;
++ }
++
++ QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial()
++ : QSGDistanceFieldTextMaterial()
++ {
++ }
++
++ QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial()
++ {
++ }
++
++ void QSGDistanceFieldStyledTextMaterial::setStyleColor(const QColor &color)
++ {
++ float r, g, b, a;
++ color.getRgbF(&r, &g, &b, &a);
++ m_styleColor = QVector4D(r * a, g * a, b * a, a);
++ }
++
++ int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const
++ {
++ Q_ASSERT(o && type() == o->type());
++ const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o);
++ if (m_styleColor != other->m_styleColor)
++ return &m_styleColor < &other->m_styleColor ? -1 : 1;
++ return QSGDistanceFieldTextMaterial::compare(o);
++ }
++
++ class DistanceFieldOutlineTextMaterialRhiShader : public DistanceFieldStyledTextMaterialRhiShader
++ {
++ public:
++ DistanceFieldOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount);
++
++ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++ };
++
++ DistanceFieldOutlineTextMaterialRhiShader::DistanceFieldOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : DistanceFieldStyledTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb"), viewCount);
++ }
++
++ class DistanceFieldAnisotropicOutlineTextMaterialRhiShader : public DistanceFieldOutlineTextMaterialRhiShader
++ {
++ public:
++ DistanceFieldAnisotropicOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount);
++ };
++
++ DistanceFieldAnisotropicOutlineTextMaterialRhiShader::DistanceFieldAnisotropicOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : DistanceFieldOutlineTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext_a_fwidth.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext_fwidth.frag.qsb"), viewCount);
++ }
++
++ bool DistanceFieldOutlineTextMaterialRhiShader::updateUniformData(RenderState &state,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
++ {
++ bool changed = DistanceFieldStyledTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
++ QSGDistanceFieldOutlineTextMaterial *mat = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newMaterial);
++ QSGDistanceFieldOutlineTextMaterial *oldMat = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldMaterial);
++
++ QByteArray *buf = state.uniformData();
++ Q_ASSERT(buf->size() >= 136);
++
++ if (!oldMat || mat->fontScale() != oldMat->fontScale() || state.isMatrixDirty()) {
++ float dfRadius = mat->glyphCache()->distanceFieldRadius();
++ float combinedScale = m_fontScale * m_matrixScale;
++ float base = thresholdFunc(combinedScale);
++ float range = spreadFunc(combinedScale);
++ float outlineLimit = qMax(0.2f, base - 0.5f / dfRadius / m_fontScale);
++ float alphaMin = qMax(0.0f, base - range);
++ float styleAlphaMin0 = qMax(0.0f, outlineLimit - range);
++ float styleAlphaMin1 = qMin(outlineLimit + range, alphaMin);
++ memcpy(buf->data() + m_currentUbufOffset, &styleAlphaMin0, 4);
++ memcpy(buf->data() + m_currentUbufOffset + 4, &styleAlphaMin1, 4);
++ changed = true;
++ }
++
++ return changed;
++ }
++
++ QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial()
++ : QSGDistanceFieldStyledTextMaterial()
++ {
++ }
++
++ QSGDistanceFieldOutlineTextMaterial::~QSGDistanceFieldOutlineTextMaterial()
++ {
++ }
++
++ QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const
++ {
++ static QSGMaterialType type;
++ return &type;
++ }
++
++ QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
++ {
++ if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported())
++ return new DistanceFieldAnisotropicOutlineTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ else
++ return new DistanceFieldOutlineTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ }
++
++ class DistanceFieldShiftedStyleTextMaterialRhiShader : public DistanceFieldStyledTextMaterialRhiShader
++ {
++ public:
++ DistanceFieldShiftedStyleTextMaterialRhiShader(bool alphaTexture, int viewCount);
++
++ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++ };
++
++ DistanceFieldShiftedStyleTextMaterialRhiShader::DistanceFieldShiftedStyleTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : DistanceFieldStyledTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb"), viewCount);
++ }
++
++ bool DistanceFieldShiftedStyleTextMaterialRhiShader::updateUniformData(RenderState &state,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
++ {
++ bool changed = DistanceFieldStyledTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
++ QSGDistanceFieldShiftedStyleTextMaterial *mat = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newMaterial);
++ QSGDistanceFieldShiftedStyleTextMaterial *oldMat = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldMaterial);
++
++ QByteArray *buf = state.uniformData();
++ Q_ASSERT(buf->size() >= 136);
++
++ if (!oldMat || oldMat->fontScale() != mat->fontScale() || oldMat->shift() != mat->shift()
++ || oldMat->textureSize() != mat->textureSize())
++ {
++ QVector2D shift(1.0 / mat->fontScale() * mat->shift().x(),
++ 1.0 / mat->fontScale() * mat->shift().y());
++ memcpy(buf->data() + m_currentUbufOffset, &shift, 8);
++ changed = true;
++ }
++
++ return changed;
++ }
++
++ class DistanceFieldAnisotropicShiftedTextMaterialRhiShader : public DistanceFieldShiftedStyleTextMaterialRhiShader
++ {
++ public:
++ DistanceFieldAnisotropicShiftedTextMaterialRhiShader(bool alphaTexture, int viewCount);
++ };
++
++ DistanceFieldAnisotropicShiftedTextMaterialRhiShader::DistanceFieldAnisotropicShiftedTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : DistanceFieldShiftedStyleTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext_a_fwidth.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext_fwidth.frag.qsb"), viewCount);
++ }
++
++ QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
++ : QSGDistanceFieldStyledTextMaterial()
++ {
++ }
++
++ QSGDistanceFieldShiftedStyleTextMaterial::~QSGDistanceFieldShiftedStyleTextMaterial()
++ {
++ }
++
++ QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const
++ {
++ static QSGMaterialType type;
++ return &type;
++ }
++
++ QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
++ {
++ if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported())
++ return new DistanceFieldAnisotropicShiftedTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ else
++ return new DistanceFieldShiftedStyleTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ }
++
++ int QSGDistanceFieldShiftedStyleTextMaterial::compare(const QSGMaterial *o) const
++ {
++ const QSGDistanceFieldShiftedStyleTextMaterial *other = static_cast<const QSGDistanceFieldShiftedStyleTextMaterial *>(o);
++ if (m_shift != other->m_shift)
++ return &m_shift < &other->m_shift ? -1 : 1;
++ return QSGDistanceFieldStyledTextMaterial::compare(o);
++ }
++
++ class QSGHiQSubPixelDistanceFieldTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader
++ {
++ public:
++ QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount);
++
++ bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++ bool updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
++ };
++
++ QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setFlag(UpdatesGraphicsPipelineState, true);
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb"), viewCount);
++ }
++
++ bool QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::updateUniformData(RenderState &state,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
++ {
++ bool changed = QSGDistanceFieldTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial);
++ QSGHiQSubPixelDistanceFieldTextMaterial *mat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(newMaterial);
++ QSGHiQSubPixelDistanceFieldTextMaterial *oldMat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(oldMaterial);
++
++ QByteArray *buf = state.uniformData();
++ Q_ASSERT(buf->size() >= 128);
++
++ if (!oldMat || mat->fontScale() != oldMat->fontScale()) {
++ float fontScale = mat->fontScale();
++ memcpy(buf->data() + m_currentUbufOffset, &fontScale, 4);
++ changed = true;
++ }
++ m_currentUbufOffset += 4 + 4; // 4 for padding for vec2 alignment
++
++ if (!oldMat || state.isMatrixDirty()) {
++ int viewportWidth = state.viewportRect().width();
++ QMatrix4x4 mat = state.combinedMatrix().inverted();
++ QVector4D vecDelta = mat.column(0) * (qreal(2) / viewportWidth);
++ memcpy(buf->data() + m_currentUbufOffset, &vecDelta, 16);
++ }
++
++ return changed;
++ }
++
++ bool QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps,
++ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
++ {
++ Q_UNUSED(state);
++ Q_UNUSED(oldMaterial);
++ QSGHiQSubPixelDistanceFieldTextMaterial *mat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(newMaterial);
++
++ ps->blendEnable = true;
++ ps->srcColor = GraphicsPipelineState::ConstantColor;
++ ps->dstColor = GraphicsPipelineState::OneMinusSrcColor;
++
++ const QVector4D color = mat->color();
++ // this is dynamic state but it's - magic! - taken care of by the renderer
++ ps->blendConstant = QColor::fromRgbF(color.x(), color.y(), color.z(), 1.0f);
++
++ return true;
++ }
++
++ QSGMaterialType *QSGHiQSubPixelDistanceFieldTextMaterial::type() const
++ {
++ static QSGMaterialType type;
++ return &type;
++ }
++
++ QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
++ {
++ if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported())
++ return new DistanceFieldAnisotropicTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ else
++ return new QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ }
++
++ class QSGLoQSubPixelDistanceFieldTextMaterialRhiShader : public QSGHiQSubPixelDistanceFieldTextMaterialRhiShader
++ {
++ public:
++ QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount);
++ };
++
++ QSGLoQSubPixelDistanceFieldTextMaterialRhiShader::QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount)
++ : QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount)
++ {
++ setShaderFileName(VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb"), viewCount);
++ if (alphaTexture)
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb"), viewCount);
++ else
++ setShaderFileName(FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb"), viewCount);
++ }
++
++ QSGMaterialType *QSGLoQSubPixelDistanceFieldTextMaterial::type() const
++ {
++ static QSGMaterialType type;
++ return &type;
++ }
++
++ QSGMaterialShader *QSGLoQSubPixelDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
++ {
++ if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported())
++ return new DistanceFieldAnisotropicTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ else
++ return new QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount());
++ }
++
++ QT_END_NAMESPACE