diff options
Diffstat (limited to 'src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp')
-rw-r--r-- | src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp | 655 |
1 files changed, 322 insertions, 333 deletions
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp index aa58218505..afb41f32e4 100644 --- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -1,92 +1,14 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// 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 #include "qsgdistancefieldglyphnode_p_p.h" -#include <QtQuick/private/qsgtexture_p.h> -#include <QtGui/qopenglfunctions.h> +#include "qsgrhidistancefieldglyphcache_p.h" #include <QtGui/qsurface.h> #include <QtGui/qwindow.h> #include <qmath.h> QT_BEGIN_NAMESPACE -class QSGDistanceFieldTextMaterialShader : public QSGMaterialShader -{ -public: - QSGDistanceFieldTextMaterialShader(); - - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; - char const *const *attributeNames() const override; - -protected: - void initialize() override; - - void updateAlphaRange(); - void updateColor(const QVector4D &c); - void updateTextureScale(const QVector2D &ts); - - float m_fontScale = 1.0; - float m_matrixScale = 1.0; - - int m_matrix_id = -1; - int m_textureScale_id = -1; - int m_alphaMin_id = -1; - int m_alphaMax_id = -1; - int m_color_id = -1; - - QVector2D m_lastTextureScale; - QVector4D m_lastColor; - float m_lastAlphaMin = -1; - float m_lastAlphaMax = -1; -}; - -char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const { - static char const *const attr[] = { "vCoord", "tCoord", nullptr }; - return attr; -} - -QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader() -{ - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldtext.frag")); -} - static float qt_sg_envFloat(const char *name, float defaultValue) { if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) @@ -111,112 +33,140 @@ static float spreadFunc(float glyphScale) return range / glyphScale; } -void QSGDistanceFieldTextMaterialShader::updateAlphaRange() +class QSGDistanceFieldTextMaterialRhiShader : public QSGMaterialShader { - float combinedScale = m_fontScale * m_matrixScale; - float base = thresholdFunc(combinedScale); - float range = spreadFunc(combinedScale); - float alphaMin = qMax(0.0f, base - range); - float alphaMax = qMin(base + range, 1.0f); - if (alphaMin != m_lastAlphaMin) { - program()->setUniformValue(m_alphaMin_id, GLfloat(alphaMin)); - m_lastAlphaMin = alphaMin; - } - if (alphaMax != m_lastAlphaMax) { - program()->setUniformValue(m_alphaMax_id, GLfloat(alphaMax)); - m_lastAlphaMax = alphaMax; - } -} +public: + QSGDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount); -void QSGDistanceFieldTextMaterialShader::updateColor(const QVector4D &c) -{ - if (m_lastColor != c) { - program()->setUniformValue(m_color_id, c); - m_lastColor = c; - } -} + bool updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; -void QSGDistanceFieldTextMaterialShader::updateTextureScale(const QVector2D &ts) -{ - if (m_lastTextureScale != ts) { - program()->setUniformValue(m_textureScale_id, ts); - m_lastTextureScale = ts; - } -} + void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; -void QSGDistanceFieldTextMaterialShader::initialize() +protected: + float m_fontScale = 1.0; + float m_matrixScale = 1.0; + quint32 m_currentUbufOffset; +}; + +QSGDistanceFieldTextMaterialRhiShader::QSGDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount) { - QSGMaterialShader::initialize(); - m_matrix_id = program()->uniformLocation("matrix"); - m_textureScale_id = program()->uniformLocation("textureScale"); - m_color_id = program()->uniformLocation("color"); - m_alphaMin_id = program()->uniformLocation("alphaMin"); - m_alphaMax_id = program()->uniformLocation("alphaMax"); + 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); } -void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) +bool QSGDistanceFieldTextMaterialRhiShader::updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { - Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); - QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect); - QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect); + Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type()); + QSGDistanceFieldTextMaterial *mat = static_cast<QSGDistanceFieldTextMaterial *>(newMaterial); + QSGDistanceFieldTextMaterial *oldMat = static_cast<QSGDistanceFieldTextMaterial *>(oldMaterial); - bool updated = material->updateTextureSize(); + // 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()); - if (oldMaterial == nullptr - || material->color() != oldMaterial->color() - || state.isOpacityDirty()) { - QVector4D color = material->color(); - color *= state.opacity(); - updateColor(color); - } + bool changed = false; + QByteArray *buf = state.uniformData(); + Q_ASSERT(buf->size() >= 104); bool updateRange = false; - if (oldMaterial == nullptr - || material->fontScale() != oldMaterial->fontScale()) { - m_fontScale = material->fontScale(); + if (!oldMat || mat->fontScale() != oldMat->fontScale()) { + m_fontScale = mat->fontScale(); updateRange = true; } if (state.isMatrixDirty()) { - program()->setUniformValue(m_matrix_id, state.combinedMatrix()); m_matrixScale = qSqrt(qAbs(state.determinant())) * state.devicePixelRatio(); updateRange = true; } - if (updateRange) { - updateAlphaRange(); + 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 - Q_ASSERT(material->glyphCache()); + // move texture uploads/copies onto the renderer's soon-to-be-committed list + static_cast<QSGRhiDistanceFieldGlyphCache *>(mat->glyphCache())->commitResourceUpdates(state.resourceUpdateBatch()); - if (updated - || oldMaterial == nullptr - || oldMaterial->texture()->textureId != material->texture()->textureId) { - updateTextureScale(QVector2D(1.0 / material->textureSize().width(), - 1.0 / material->textureSize().height())); + m_currentUbufOffset = offset; + return changed; +} - QOpenGLFunctions *funcs = state.context()->functions(); - funcs->glBindTexture(GL_TEXTURE_2D, material->texture()->textureId); +void QSGDistanceFieldTextMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) +{ + Q_UNUSED(state); + if (binding != 1) + return; - if (updated) { - // Set the mag/min filters to be linear. We only need to do this when the texture - // has been recreated. - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } + 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 @@ -227,15 +177,17 @@ QSGMaterialType *QSGDistanceFieldTextMaterial::type() const void QSGDistanceFieldTextMaterial::setColor(const QColor &color) { - m_color = QVector4D(color.redF() * color.alphaF(), - color.greenF() * color.alphaF(), - color.blueF() * color.alphaF(), - color.alphaF()); + float r, g, b, a; + color.getRgbF(&r, &g, &b, &a); + m_color = QVector4D(r * a, g * a, b * a, a); } -QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const +QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const { - return new QSGDistanceFieldTextMaterialShader; + 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() @@ -246,9 +198,26 @@ bool QSGDistanceFieldTextMaterial::updateTextureSize() if (m_texture->size != m_size) { m_size = m_texture->size; return true; - } else { - return false; } + + 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 @@ -262,50 +231,47 @@ int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const } if (m_color != other->m_color) return &m_color < &other->m_color ? -1 : 1; - int t0 = m_texture ? m_texture->textureId : 0; - int t1 = other->m_texture ? other->m_texture->textureId : 0; - return t0 - t1; + 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 DistanceFieldStyledTextMaterialShader : public QSGDistanceFieldTextMaterialShader +class DistanceFieldStyledTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader { public: - DistanceFieldStyledTextMaterialShader(); - - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; - -protected: - void initialize() override; + DistanceFieldStyledTextMaterialRhiShader(bool alphaTexture, int viewCount); - int m_styleColor_id = -1; + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; }; -DistanceFieldStyledTextMaterialShader::DistanceFieldStyledTextMaterialShader() - : QSGDistanceFieldTextMaterialShader() +DistanceFieldStyledTextMaterialRhiShader::DistanceFieldStyledTextMaterialRhiShader(bool alphaTexture, int viewCount) + : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) { } -void DistanceFieldStyledTextMaterialShader::initialize() +bool DistanceFieldStyledTextMaterialRhiShader::updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { - QSGDistanceFieldTextMaterialShader::initialize(); - m_styleColor_id = program()->uniformLocation("styleColor"); -} + bool changed = QSGDistanceFieldTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); + QSGDistanceFieldStyledTextMaterial *mat = static_cast<QSGDistanceFieldStyledTextMaterial *>(newMaterial); + QSGDistanceFieldStyledTextMaterial *oldMat = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldMaterial); -void DistanceFieldStyledTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect); + 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 - QSGDistanceFieldStyledTextMaterial *material = static_cast<QSGDistanceFieldStyledTextMaterial *>(newEffect); - QSGDistanceFieldStyledTextMaterial *oldMaterial = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldEffect); + if (!oldMat || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) { + QVector4D styleColor = mat->styleColor(); + styleColor *= state.opacity(); - if (oldMaterial == nullptr - || material->styleColor() != oldMaterial->styleColor() - || (state.isOpacityDirty())) { - QVector4D color = material->styleColor(); - color *= state.opacity(); - program()->setUniformValue(m_styleColor_id, color); + memcpy(buf->data() + m_currentUbufOffset, &styleColor, 16); + changed = true; } + m_currentUbufOffset += 16; + + return changed; } QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial() @@ -319,10 +285,9 @@ QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial() void QSGDistanceFieldStyledTextMaterial::setStyleColor(const QColor &color) { - m_styleColor = QVector4D(color.redF() * color.alphaF(), - color.greenF() * color.alphaF(), - color.blueF() * color.alphaF(), - color.alphaF()); + 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 @@ -334,64 +299,67 @@ int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const return QSGDistanceFieldTextMaterial::compare(o); } - -class DistanceFieldOutlineTextMaterialShader : public DistanceFieldStyledTextMaterialShader +class DistanceFieldOutlineTextMaterialRhiShader : public DistanceFieldStyledTextMaterialRhiShader { public: - DistanceFieldOutlineTextMaterialShader(); + DistanceFieldOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount); - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; - -protected: - void initialize() override; - - void updateOutlineAlphaRange(int dfRadius); - - int m_outlineAlphaMax0_id = -1; - int m_outlineAlphaMax1_id = -1; + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; }; -DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader() - : DistanceFieldStyledTextMaterialShader() +DistanceFieldOutlineTextMaterialRhiShader::DistanceFieldOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount) + : DistanceFieldStyledTextMaterialRhiShader(alphaTexture, viewCount) { - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldoutlinetext.frag")); + 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); } -void DistanceFieldOutlineTextMaterialShader::initialize() +class DistanceFieldAnisotropicOutlineTextMaterialRhiShader : public DistanceFieldOutlineTextMaterialRhiShader { - DistanceFieldStyledTextMaterialShader::initialize(); - m_outlineAlphaMax0_id = program()->uniformLocation("outlineAlphaMax0"); - m_outlineAlphaMax1_id = program()->uniformLocation("outlineAlphaMax1"); -} - -void DistanceFieldOutlineTextMaterialShader::updateOutlineAlphaRange(int dfRadius) -{ - 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); - program()->setUniformValue(m_outlineAlphaMax0_id, GLfloat(styleAlphaMin0)); - program()->setUniformValue(m_outlineAlphaMax1_id, GLfloat(styleAlphaMin1)); -} - -void DistanceFieldOutlineTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect); +public: + DistanceFieldAnisotropicOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount); +}; - QSGDistanceFieldOutlineTextMaterial *material = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newEffect); - QSGDistanceFieldOutlineTextMaterial *oldMaterial = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldEffect); +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; + } - if (oldMaterial == nullptr - || material->fontScale() != oldMaterial->fontScale() - || state.isMatrixDirty()) - updateOutlineAlphaRange(material->glyphCache()->distanceFieldRadius()); + return changed; } - QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial() : QSGDistanceFieldStyledTextMaterial() { @@ -407,60 +375,68 @@ QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const return &type; } -QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader() const +QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const { - return new DistanceFieldOutlineTextMaterialShader; + 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 DistanceFieldShiftedStyleTextMaterialShader : public DistanceFieldStyledTextMaterialShader +class DistanceFieldShiftedStyleTextMaterialRhiShader : public DistanceFieldStyledTextMaterialRhiShader { public: - DistanceFieldShiftedStyleTextMaterialShader(); - - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; - -protected: - void initialize() override; - - void updateShift(qreal fontScale, const QPointF& shift); + DistanceFieldShiftedStyleTextMaterialRhiShader(bool alphaTexture, int viewCount); - int m_shift_id = -1; + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; }; -DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader() - : DistanceFieldStyledTextMaterialShader() +DistanceFieldShiftedStyleTextMaterialRhiShader::DistanceFieldShiftedStyleTextMaterialRhiShader(bool alphaTexture, int viewCount) + : DistanceFieldStyledTextMaterialRhiShader(alphaTexture, viewCount) { - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldshiftedtext.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/distancefieldshiftedtext.frag")); + 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); } -void DistanceFieldShiftedStyleTextMaterialShader::initialize() +bool DistanceFieldShiftedStyleTextMaterialRhiShader::updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { - DistanceFieldStyledTextMaterialShader::initialize(); - m_shift_id = program()->uniformLocation("shift"); -} + bool changed = DistanceFieldStyledTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); + QSGDistanceFieldShiftedStyleTextMaterial *mat = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newMaterial); + QSGDistanceFieldShiftedStyleTextMaterial *oldMat = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldMaterial); -void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - DistanceFieldStyledTextMaterialShader::updateState(state, newEffect, oldEffect); + QByteArray *buf = state.uniformData(); + Q_ASSERT(buf->size() >= 136); - QSGDistanceFieldShiftedStyleTextMaterial *material = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newEffect); - QSGDistanceFieldShiftedStyleTextMaterial *oldMaterial = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldEffect); - - if (oldMaterial == nullptr - || oldMaterial->fontScale() != material->fontScale() - || oldMaterial->shift() != material->shift() - || oldMaterial->textureSize() != material->textureSize()) { - updateShift(material->fontScale(), material->shift()); + 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; } -void DistanceFieldShiftedStyleTextMaterialShader::updateShift(qreal fontScale, const QPointF &shift) +class DistanceFieldAnisotropicShiftedTextMaterialRhiShader : public DistanceFieldShiftedStyleTextMaterialRhiShader +{ +public: + DistanceFieldAnisotropicShiftedTextMaterialRhiShader(bool alphaTexture, int viewCount); +}; + +DistanceFieldAnisotropicShiftedTextMaterialRhiShader::DistanceFieldAnisotropicShiftedTextMaterialRhiShader(bool alphaTexture, int viewCount) + : DistanceFieldShiftedStyleTextMaterialRhiShader(alphaTexture, viewCount) { - QPointF texel(1.0 / fontScale * shift.x(), - 1.0 / fontScale * shift.y()); - program()->setUniformValue(m_shift_id, texel); + 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() @@ -478,9 +454,12 @@ QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const return &type; } -QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() const +QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const { - return new DistanceFieldShiftedStyleTextMaterialShader; + 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 @@ -491,68 +470,70 @@ int QSGDistanceFieldShiftedStyleTextMaterial::compare(const QSGMaterial *o) cons return QSGDistanceFieldStyledTextMaterial::compare(o); } -class QSGHiQSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader +class QSGHiQSubPixelDistanceFieldTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader { public: - QSGHiQSubPixelDistanceFieldTextMaterialShader(); - - void initialize() override; - void activate() override; - void deactivate() override; - void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount); -private: - int m_fontScale_id = -1; - int m_vecDelta_id = -1; + bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; + bool updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; }; -QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader() - : QSGDistanceFieldTextMaterialShader() +QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount) + : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) { - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag")); + 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); } -void QSGHiQSubPixelDistanceFieldTextMaterialShader::initialize() +bool QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) { - QSGDistanceFieldTextMaterialShader::initialize(); - m_fontScale_id = program()->uniformLocation("fontScale"); - m_vecDelta_id = program()->uniformLocation("vecDelta"); -} + bool changed = QSGDistanceFieldTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); + QSGHiQSubPixelDistanceFieldTextMaterial *mat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(newMaterial); + QSGHiQSubPixelDistanceFieldTextMaterial *oldMat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(oldMaterial); -void QSGHiQSubPixelDistanceFieldTextMaterialShader::activate() -{ - QSGDistanceFieldTextMaterialShader::activate(); - QOpenGLContext::currentContext()->functions()->glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); -} + QByteArray *buf = state.uniformData(); + Q_ASSERT(buf->size() >= 128); -void QSGHiQSubPixelDistanceFieldTextMaterialShader::deactivate() -{ - QSGDistanceFieldTextMaterialShader::deactivate(); - QOpenGLContext::currentContext()->functions()->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); -} - -void QSGHiQSubPixelDistanceFieldTextMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) -{ - Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); - QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect); - QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect); - - if (oldMaterial == nullptr || material->color() != oldMaterial->color()) { - QVector4D c = material->color(); - state.context()->functions()->glBlendColor(c.x(), c.y(), c.z(), 1.0f); + 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 (oldMaterial == nullptr || material->fontScale() != oldMaterial->fontScale()) - program()->setUniformValue(m_fontScale_id, GLfloat(material->fontScale())); - - if (oldMaterial == nullptr || state.isMatrixDirty()) { + if (!oldMat || state.isMatrixDirty()) { int viewportWidth = state.viewportRect().width(); QMatrix4x4 mat = state.combinedMatrix().inverted(); - program()->setUniformValue(m_vecDelta_id, mat.column(0) * (qreal(2) / viewportWidth)); + QVector4D vecDelta = mat.column(0) * (qreal(2) / viewportWidth); + memcpy(buf->data() + m_currentUbufOffset, &vecDelta, 16); } - QSGDistanceFieldTextMaterialShader::updateState(state, newEffect, oldEffect); + 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 @@ -561,23 +542,28 @@ QSGMaterialType *QSGHiQSubPixelDistanceFieldTextMaterial::type() const return &type; } -QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader() const +QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const { - return new QSGHiQSubPixelDistanceFieldTextMaterialShader; + 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 QSGLoQSubPixelDistanceFieldTextMaterialShader : public QSGHiQSubPixelDistanceFieldTextMaterialShader +class QSGLoQSubPixelDistanceFieldTextMaterialRhiShader : public QSGHiQSubPixelDistanceFieldTextMaterialRhiShader { public: - QSGLoQSubPixelDistanceFieldTextMaterialShader(); + QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount); }; -QSGLoQSubPixelDistanceFieldTextMaterialShader::QSGLoQSubPixelDistanceFieldTextMaterialShader() - : QSGHiQSubPixelDistanceFieldTextMaterialShader() +QSGLoQSubPixelDistanceFieldTextMaterialRhiShader::QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount) + : QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) { - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/loqsubpixeldistancefieldtext.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/loqsubpixeldistancefieldtext.frag")); + 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 @@ -586,9 +572,12 @@ QSGMaterialType *QSGLoQSubPixelDistanceFieldTextMaterial::type() const return &type; } -QSGMaterialShader *QSGLoQSubPixelDistanceFieldTextMaterial::createShader() const +QSGMaterialShader *QSGLoQSubPixelDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const { - return new QSGLoQSubPixelDistanceFieldTextMaterialShader; + 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 |