| 1 | // Copyright (C) 2019 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
| 3 | |
| 4 | #include "qsgdistancefieldglyphnode_p_p.h" |
| 5 | #include "qsgrhidistancefieldglyphcache_p.h" |
| 6 | #include <QtGui/qsurface.h> |
| 7 | #include <QtGui/qwindow.h> |
| 8 | #include <qmath.h> |
| 9 | |
| 10 | QT_BEGIN_NAMESPACE |
| 11 | |
| 12 | static float qt_sg_envFloat(const char *name, float defaultValue) |
| 13 | { |
| 14 | if (Q_LIKELY(!qEnvironmentVariableIsSet(name))) |
| 15 | return defaultValue; |
| 16 | bool ok = false; |
| 17 | const float value = qgetenv(varName: name).toFloat(ok: &ok); |
| 18 | return ok ? value : defaultValue; |
| 19 | } |
| 20 | |
| 21 | static float thresholdFunc(float glyphScale) |
| 22 | { |
| 23 | static const float base = qt_sg_envFloat(name: "QT_DF_BASE" , defaultValue: 0.5f); |
| 24 | static const float baseDev = qt_sg_envFloat(name: "QT_DF_BASEDEVIATION" , defaultValue: 0.065f); |
| 25 | static const float devScaleMin = qt_sg_envFloat(name: "QT_DF_SCALEFORMAXDEV" , defaultValue: 0.15f); |
| 26 | static const float devScaleMax = qt_sg_envFloat(name: "QT_DF_SCALEFORNODEV" , defaultValue: 0.3f); |
| 27 | return base - ((qBound(min: devScaleMin, val: glyphScale, max: devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev); |
| 28 | } |
| 29 | |
| 30 | static float spreadFunc(float glyphScale) |
| 31 | { |
| 32 | static const float range = qt_sg_envFloat(name: "QT_DF_RANGE" , defaultValue: 0.06f); |
| 33 | return range / glyphScale; |
| 34 | } |
| 35 | |
| 36 | class QSGDistanceFieldTextMaterialRhiShader : public QSGMaterialShader |
| 37 | { |
| 38 | public: |
| 39 | QSGDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 40 | |
| 41 | bool updateUniformData(RenderState &state, |
| 42 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 43 | |
| 44 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
| 45 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 46 | |
| 47 | protected: |
| 48 | float m_fontScale = 1.0; |
| 49 | float m_matrixScale = 1.0; |
| 50 | quint32 m_currentUbufOffset; |
| 51 | }; |
| 52 | |
| 53 | QSGDistanceFieldTextMaterialRhiShader::QSGDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 54 | { |
| 55 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext.vert.qsb" ), viewCount); |
| 56 | if (alphaTexture) |
| 57 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext_a.frag.qsb" ), viewCount); |
| 58 | else |
| 59 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext.frag.qsb" ), viewCount); |
| 60 | } |
| 61 | |
| 62 | bool QSGDistanceFieldTextMaterialRhiShader::updateUniformData(RenderState &state, |
| 63 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
| 64 | { |
| 65 | Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type()); |
| 66 | QSGDistanceFieldTextMaterial *mat = static_cast<QSGDistanceFieldTextMaterial *>(newMaterial); |
| 67 | QSGDistanceFieldTextMaterial *oldMat = static_cast<QSGDistanceFieldTextMaterial *>(oldMaterial); |
| 68 | |
| 69 | // updateUniformData() is called before updateSampledImage() by the |
| 70 | // renderer. Hence updating the glyph cache stuff here. |
| 71 | const bool textureUpdated = mat->updateTextureSizeAndWrapper(); |
| 72 | Q_ASSERT(mat->wrapperTexture()); |
| 73 | Q_ASSERT(oldMat == nullptr || oldMat->texture()); |
| 74 | |
| 75 | bool changed = false; |
| 76 | QByteArray *buf = state.uniformData(); |
| 77 | Q_ASSERT(buf->size() >= 104); |
| 78 | |
| 79 | bool updateRange = false; |
| 80 | if (!oldMat || mat->fontScale() != oldMat->fontScale()) { |
| 81 | m_fontScale = mat->fontScale(); |
| 82 | updateRange = true; |
| 83 | } |
| 84 | if (state.isMatrixDirty()) { |
| 85 | m_matrixScale = qSqrt(v: qAbs(t: state.determinant())) * state.devicePixelRatio(); |
| 86 | updateRange = true; |
| 87 | } |
| 88 | quint32 offset = 0; |
| 89 | const int matrixCount = qMin(a: state.projectionMatrixCount(), b: newMaterial->viewCount()); |
| 90 | for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) { |
| 91 | if (state.isMatrixDirty()) { |
| 92 | const QMatrix4x4 m = state.combinedMatrix(index: viewIndex); |
| 93 | memcpy(dest: buf->data() + 64 * viewIndex, src: m.constData(), n: 64); |
| 94 | changed = true; |
| 95 | } |
| 96 | offset += 64; |
| 97 | } |
| 98 | if (textureUpdated || !oldMat || oldMat->texture()->texture != mat->texture()->texture) { |
| 99 | const QVector2D ts(1.0f / mat->textureSize().width(), 1.0f / mat->textureSize().height()); |
| 100 | Q_ASSERT(sizeof(ts) == 8); |
| 101 | memcpy(dest: buf->data() + offset, src: &ts, n: 8); |
| 102 | changed = true; |
| 103 | } |
| 104 | offset += 8 + 8; // 8 is padding for vec4 alignment |
| 105 | if (!oldMat || mat->color() != oldMat->color() || state.isOpacityDirty()) { |
| 106 | const QVector4D color = mat->color() * state.opacity(); |
| 107 | Q_ASSERT(sizeof(color) == 16); |
| 108 | memcpy(dest: buf->data() + offset, src: &color, n: 16); |
| 109 | changed = true; |
| 110 | } |
| 111 | offset += 16; |
| 112 | if (updateRange) { // deferred because depends on m_fontScale and m_matrixScale |
| 113 | const float combinedScale = m_fontScale * m_matrixScale; |
| 114 | const float base = thresholdFunc(glyphScale: combinedScale); |
| 115 | const float range = spreadFunc(glyphScale: combinedScale); |
| 116 | const QVector2D alphaMinMax(qMax(a: 0.0f, b: base - range), qMin(a: base + range, b: 1.0f)); |
| 117 | memcpy(dest: buf->data() + offset, src: &alphaMinMax, n: 8); |
| 118 | changed = true; |
| 119 | } |
| 120 | offset += 8; // not adding any padding here since we are not sure what comes afterwards in the subclasses' shaders |
| 121 | |
| 122 | // move texture uploads/copies onto the renderer's soon-to-be-committed list |
| 123 | static_cast<QSGRhiDistanceFieldGlyphCache *>(mat->glyphCache())->commitResourceUpdates(mergeInto: state.resourceUpdateBatch()); |
| 124 | |
| 125 | m_currentUbufOffset = offset; |
| 126 | return changed; |
| 127 | } |
| 128 | |
| 129 | void QSGDistanceFieldTextMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
| 130 | QSGMaterial *newMaterial, QSGMaterial *) |
| 131 | { |
| 132 | Q_UNUSED(state); |
| 133 | if (binding != 1) |
| 134 | return; |
| 135 | |
| 136 | QSGDistanceFieldTextMaterial *mat = static_cast<QSGDistanceFieldTextMaterial *>(newMaterial); |
| 137 | QSGTexture *t = mat->wrapperTexture(); |
| 138 | t->setFiltering(QSGTexture::Linear); |
| 139 | *texture = t; |
| 140 | } |
| 141 | |
| 142 | class DistanceFieldAnisotropicTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader |
| 143 | { |
| 144 | public: |
| 145 | DistanceFieldAnisotropicTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 146 | }; |
| 147 | |
| 148 | DistanceFieldAnisotropicTextMaterialRhiShader::DistanceFieldAnisotropicTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 149 | : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) |
| 150 | { |
| 151 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext.vert.qsb" ), viewCount); |
| 152 | if (alphaTexture) |
| 153 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext_a_fwidth.frag.qsb" ), viewCount); |
| 154 | else |
| 155 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldtext_fwidth.frag.qsb" ), viewCount); |
| 156 | } |
| 157 | |
| 158 | QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial() |
| 159 | : m_glyph_cache(nullptr) |
| 160 | , m_texture(nullptr) |
| 161 | , m_fontScale(1.0) |
| 162 | , m_sgTexture(nullptr) |
| 163 | { |
| 164 | setFlag(flags: Blending | RequiresDeterminant, on: true); |
| 165 | } |
| 166 | |
| 167 | QSGDistanceFieldTextMaterial::~QSGDistanceFieldTextMaterial() |
| 168 | { |
| 169 | delete m_sgTexture; |
| 170 | } |
| 171 | |
| 172 | QSGMaterialType *QSGDistanceFieldTextMaterial::type() const |
| 173 | { |
| 174 | static QSGMaterialType type; |
| 175 | return &type; |
| 176 | } |
| 177 | |
| 178 | void QSGDistanceFieldTextMaterial::setColor(const QColor &color) |
| 179 | { |
| 180 | float r, g, b, a; |
| 181 | color.getRgbF(r: &r, g: &g, b: &b, a: &a); |
| 182 | m_color = QVector4D(r * a, g * a, b * a, a); |
| 183 | } |
| 184 | |
| 185 | QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
| 186 | { |
| 187 | if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported()) |
| 188 | return new DistanceFieldAnisotropicTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 189 | else |
| 190 | return new QSGDistanceFieldTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 191 | } |
| 192 | |
| 193 | bool QSGDistanceFieldTextMaterial::updateTextureSize() |
| 194 | { |
| 195 | if (!m_texture) |
| 196 | m_texture = m_glyph_cache->glyphTexture(glyph: 0); // invalid texture |
| 197 | |
| 198 | if (m_texture->size != m_size) { |
| 199 | m_size = m_texture->size; |
| 200 | return true; |
| 201 | } |
| 202 | |
| 203 | return false; |
| 204 | } |
| 205 | |
| 206 | // When using the RHI we need a QSGTexture wrapping the QRhiTexture, just |
| 207 | // exposing a QRhiTexture * (which would be the equivalent of GLuint textureId) |
| 208 | // is not sufficient to play nice with the material. |
| 209 | bool QSGDistanceFieldTextMaterial::updateTextureSizeAndWrapper() |
| 210 | { |
| 211 | bool updated = updateTextureSize(); |
| 212 | if (updated) { |
| 213 | if (m_sgTexture) |
| 214 | delete m_sgTexture; |
| 215 | m_sgTexture = new QSGPlainTexture; |
| 216 | m_sgTexture->setTexture(m_texture->texture); |
| 217 | m_sgTexture->setTextureSize(m_size); |
| 218 | m_sgTexture->setOwnsTexture(false); |
| 219 | } |
| 220 | return updated; |
| 221 | } |
| 222 | |
| 223 | int QSGDistanceFieldTextMaterial::compare(const QSGMaterial *o) const |
| 224 | { |
| 225 | Q_ASSERT(o && type() == o->type()); |
| 226 | const QSGDistanceFieldTextMaterial *other = static_cast<const QSGDistanceFieldTextMaterial *>(o); |
| 227 | if (m_glyph_cache != other->m_glyph_cache) |
| 228 | return m_glyph_cache - other->m_glyph_cache; |
| 229 | if (m_fontScale != other->m_fontScale) { |
| 230 | return int(other->m_fontScale < m_fontScale) - int(m_fontScale < other->m_fontScale); |
| 231 | } |
| 232 | if (m_color != other->m_color) |
| 233 | return &m_color < &other->m_color ? -1 : 1; |
| 234 | qintptr t0 = m_texture ? qintptr(m_texture->texture) : 0; |
| 235 | qintptr t1 = other->m_texture ? qintptr(other->m_texture->texture) : 0; |
| 236 | const qintptr diff = t0 - t1; |
| 237 | return diff < 0 ? -1 : (diff > 0 ? 1 : 0); |
| 238 | } |
| 239 | class DistanceFieldStyledTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader |
| 240 | { |
| 241 | public: |
| 242 | DistanceFieldStyledTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 243 | |
| 244 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 245 | }; |
| 246 | |
| 247 | DistanceFieldStyledTextMaterialRhiShader::DistanceFieldStyledTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 248 | : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) |
| 249 | { |
| 250 | } |
| 251 | |
| 252 | bool DistanceFieldStyledTextMaterialRhiShader::updateUniformData(RenderState &state, |
| 253 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
| 254 | { |
| 255 | bool changed = QSGDistanceFieldTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); |
| 256 | QSGDistanceFieldStyledTextMaterial *mat = static_cast<QSGDistanceFieldStyledTextMaterial *>(newMaterial); |
| 257 | QSGDistanceFieldStyledTextMaterial *oldMat = static_cast<QSGDistanceFieldStyledTextMaterial *>(oldMaterial); |
| 258 | |
| 259 | QByteArray *buf = state.uniformData(); |
| 260 | Q_ASSERT(buf->size() >= 128); |
| 261 | |
| 262 | // must add 8 bytes padding for vec4 alignment, the base class did not do this |
| 263 | m_currentUbufOffset += 8; // now at StyleColor |
| 264 | |
| 265 | if (!oldMat || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) { |
| 266 | QVector4D styleColor = mat->styleColor(); |
| 267 | styleColor *= state.opacity(); |
| 268 | |
| 269 | memcpy(dest: buf->data() + m_currentUbufOffset, src: &styleColor, n: 16); |
| 270 | changed = true; |
| 271 | } |
| 272 | m_currentUbufOffset += 16; |
| 273 | |
| 274 | return changed; |
| 275 | } |
| 276 | |
| 277 | QSGDistanceFieldStyledTextMaterial::QSGDistanceFieldStyledTextMaterial() |
| 278 | : QSGDistanceFieldTextMaterial() |
| 279 | { |
| 280 | } |
| 281 | |
| 282 | QSGDistanceFieldStyledTextMaterial::~QSGDistanceFieldStyledTextMaterial() |
| 283 | { |
| 284 | } |
| 285 | |
| 286 | void QSGDistanceFieldStyledTextMaterial::setStyleColor(const QColor &color) |
| 287 | { |
| 288 | float r, g, b, a; |
| 289 | color.getRgbF(r: &r, g: &g, b: &b, a: &a); |
| 290 | m_styleColor = QVector4D(r * a, g * a, b * a, a); |
| 291 | } |
| 292 | |
| 293 | int QSGDistanceFieldStyledTextMaterial::compare(const QSGMaterial *o) const |
| 294 | { |
| 295 | Q_ASSERT(o && type() == o->type()); |
| 296 | const QSGDistanceFieldStyledTextMaterial *other = static_cast<const QSGDistanceFieldStyledTextMaterial *>(o); |
| 297 | if (m_styleColor != other->m_styleColor) |
| 298 | return &m_styleColor < &other->m_styleColor ? -1 : 1; |
| 299 | return QSGDistanceFieldTextMaterial::compare(o); |
| 300 | } |
| 301 | |
| 302 | class DistanceFieldOutlineTextMaterialRhiShader : public DistanceFieldStyledTextMaterialRhiShader |
| 303 | { |
| 304 | public: |
| 305 | DistanceFieldOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 306 | |
| 307 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 308 | }; |
| 309 | |
| 310 | DistanceFieldOutlineTextMaterialRhiShader::DistanceFieldOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 311 | : DistanceFieldStyledTextMaterialRhiShader(alphaTexture, viewCount) |
| 312 | { |
| 313 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb" ), viewCount); |
| 314 | if (alphaTexture) |
| 315 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext_a.frag.qsb" ), viewCount); |
| 316 | else |
| 317 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext.frag.qsb" ), viewCount); |
| 318 | } |
| 319 | |
| 320 | class DistanceFieldAnisotropicOutlineTextMaterialRhiShader : public DistanceFieldOutlineTextMaterialRhiShader |
| 321 | { |
| 322 | public: |
| 323 | DistanceFieldAnisotropicOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 324 | }; |
| 325 | |
| 326 | DistanceFieldAnisotropicOutlineTextMaterialRhiShader::DistanceFieldAnisotropicOutlineTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 327 | : DistanceFieldOutlineTextMaterialRhiShader(alphaTexture, viewCount) |
| 328 | { |
| 329 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext.vert.qsb" ), viewCount); |
| 330 | if (alphaTexture) |
| 331 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext_a_fwidth.frag.qsb" ), viewCount); |
| 332 | else |
| 333 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldoutlinetext_fwidth.frag.qsb" ), viewCount); |
| 334 | } |
| 335 | |
| 336 | bool DistanceFieldOutlineTextMaterialRhiShader::updateUniformData(RenderState &state, |
| 337 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
| 338 | { |
| 339 | bool changed = DistanceFieldStyledTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); |
| 340 | QSGDistanceFieldOutlineTextMaterial *mat = static_cast<QSGDistanceFieldOutlineTextMaterial *>(newMaterial); |
| 341 | QSGDistanceFieldOutlineTextMaterial *oldMat = static_cast<QSGDistanceFieldOutlineTextMaterial *>(oldMaterial); |
| 342 | |
| 343 | QByteArray *buf = state.uniformData(); |
| 344 | Q_ASSERT(buf->size() >= 136); |
| 345 | |
| 346 | if (!oldMat || mat->fontScale() != oldMat->fontScale() || state.isMatrixDirty()) { |
| 347 | float dfRadius = mat->glyphCache()->distanceFieldRadius(); |
| 348 | float combinedScale = m_fontScale * m_matrixScale; |
| 349 | float base = thresholdFunc(glyphScale: combinedScale); |
| 350 | float range = spreadFunc(glyphScale: combinedScale); |
| 351 | float outlineLimit = qMax(a: 0.2f, b: base - 0.5f / dfRadius / m_fontScale); |
| 352 | float alphaMin = qMax(a: 0.0f, b: base - range); |
| 353 | float styleAlphaMin0 = qMax(a: 0.0f, b: outlineLimit - range); |
| 354 | float styleAlphaMin1 = qMin(a: outlineLimit + range, b: alphaMin); |
| 355 | memcpy(dest: buf->data() + m_currentUbufOffset, src: &styleAlphaMin0, n: 4); |
| 356 | memcpy(dest: buf->data() + m_currentUbufOffset + 4, src: &styleAlphaMin1, n: 4); |
| 357 | changed = true; |
| 358 | } |
| 359 | |
| 360 | return changed; |
| 361 | } |
| 362 | |
| 363 | QSGDistanceFieldOutlineTextMaterial::QSGDistanceFieldOutlineTextMaterial() |
| 364 | : QSGDistanceFieldStyledTextMaterial() |
| 365 | { |
| 366 | } |
| 367 | |
| 368 | QSGDistanceFieldOutlineTextMaterial::~QSGDistanceFieldOutlineTextMaterial() |
| 369 | { |
| 370 | } |
| 371 | |
| 372 | QSGMaterialType *QSGDistanceFieldOutlineTextMaterial::type() const |
| 373 | { |
| 374 | static QSGMaterialType type; |
| 375 | return &type; |
| 376 | } |
| 377 | |
| 378 | QSGMaterialShader *QSGDistanceFieldOutlineTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
| 379 | { |
| 380 | if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported()) |
| 381 | return new DistanceFieldAnisotropicOutlineTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 382 | else |
| 383 | return new DistanceFieldOutlineTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 384 | } |
| 385 | |
| 386 | class DistanceFieldShiftedStyleTextMaterialRhiShader : public DistanceFieldStyledTextMaterialRhiShader |
| 387 | { |
| 388 | public: |
| 389 | DistanceFieldShiftedStyleTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 390 | |
| 391 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 392 | }; |
| 393 | |
| 394 | DistanceFieldShiftedStyleTextMaterialRhiShader::DistanceFieldShiftedStyleTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 395 | : DistanceFieldStyledTextMaterialRhiShader(alphaTexture, viewCount) |
| 396 | { |
| 397 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb" ), viewCount); |
| 398 | if (alphaTexture) |
| 399 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext_a.frag.qsb" ), viewCount); |
| 400 | else |
| 401 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext.frag.qsb" ), viewCount); |
| 402 | } |
| 403 | |
| 404 | bool DistanceFieldShiftedStyleTextMaterialRhiShader::updateUniformData(RenderState &state, |
| 405 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
| 406 | { |
| 407 | bool changed = DistanceFieldStyledTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); |
| 408 | QSGDistanceFieldShiftedStyleTextMaterial *mat = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(newMaterial); |
| 409 | QSGDistanceFieldShiftedStyleTextMaterial *oldMat = static_cast<QSGDistanceFieldShiftedStyleTextMaterial *>(oldMaterial); |
| 410 | |
| 411 | QByteArray *buf = state.uniformData(); |
| 412 | Q_ASSERT(buf->size() >= 136); |
| 413 | |
| 414 | if (!oldMat || oldMat->fontScale() != mat->fontScale() || oldMat->shift() != mat->shift() |
| 415 | || oldMat->textureSize() != mat->textureSize()) |
| 416 | { |
| 417 | QVector2D shift(1.0 / mat->fontScale() * mat->shift().x(), |
| 418 | 1.0 / mat->fontScale() * mat->shift().y()); |
| 419 | memcpy(dest: buf->data() + m_currentUbufOffset, src: &shift, n: 8); |
| 420 | changed = true; |
| 421 | } |
| 422 | |
| 423 | return changed; |
| 424 | } |
| 425 | |
| 426 | class DistanceFieldAnisotropicShiftedTextMaterialRhiShader : public DistanceFieldShiftedStyleTextMaterialRhiShader |
| 427 | { |
| 428 | public: |
| 429 | DistanceFieldAnisotropicShiftedTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 430 | }; |
| 431 | |
| 432 | DistanceFieldAnisotropicShiftedTextMaterialRhiShader::DistanceFieldAnisotropicShiftedTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 433 | : DistanceFieldShiftedStyleTextMaterialRhiShader(alphaTexture, viewCount) |
| 434 | { |
| 435 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext.vert.qsb" ), viewCount); |
| 436 | if (alphaTexture) |
| 437 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext_a_fwidth.frag.qsb" ), viewCount); |
| 438 | else |
| 439 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/distancefieldshiftedtext_fwidth.frag.qsb" ), viewCount); |
| 440 | } |
| 441 | |
| 442 | QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial() |
| 443 | : QSGDistanceFieldStyledTextMaterial() |
| 444 | { |
| 445 | } |
| 446 | |
| 447 | QSGDistanceFieldShiftedStyleTextMaterial::~QSGDistanceFieldShiftedStyleTextMaterial() |
| 448 | { |
| 449 | } |
| 450 | |
| 451 | QSGMaterialType *QSGDistanceFieldShiftedStyleTextMaterial::type() const |
| 452 | { |
| 453 | static QSGMaterialType type; |
| 454 | return &type; |
| 455 | } |
| 456 | |
| 457 | QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
| 458 | { |
| 459 | if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported()) |
| 460 | return new DistanceFieldAnisotropicShiftedTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 461 | else |
| 462 | return new DistanceFieldShiftedStyleTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 463 | } |
| 464 | |
| 465 | int QSGDistanceFieldShiftedStyleTextMaterial::compare(const QSGMaterial *o) const |
| 466 | { |
| 467 | const QSGDistanceFieldShiftedStyleTextMaterial *other = static_cast<const QSGDistanceFieldShiftedStyleTextMaterial *>(o); |
| 468 | if (m_shift != other->m_shift) |
| 469 | return &m_shift < &other->m_shift ? -1 : 1; |
| 470 | return QSGDistanceFieldStyledTextMaterial::compare(o); |
| 471 | } |
| 472 | |
| 473 | class QSGHiQSubPixelDistanceFieldTextMaterialRhiShader : public QSGDistanceFieldTextMaterialRhiShader |
| 474 | { |
| 475 | public: |
| 476 | QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 477 | |
| 478 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 479 | bool updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps, |
| 480 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
| 481 | }; |
| 482 | |
| 483 | QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 484 | : QSGDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) |
| 485 | { |
| 486 | setFlag(flags: UpdatesGraphicsPipelineState, on: true); |
| 487 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.vert.qsb" ), viewCount); |
| 488 | if (alphaTexture) |
| 489 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext_a.frag.qsb" ), viewCount); |
| 490 | else |
| 491 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/hiqsubpixeldistancefieldtext.frag.qsb" ), viewCount); |
| 492 | } |
| 493 | |
| 494 | bool QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::updateUniformData(RenderState &state, |
| 495 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
| 496 | { |
| 497 | bool changed = QSGDistanceFieldTextMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); |
| 498 | QSGHiQSubPixelDistanceFieldTextMaterial *mat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(newMaterial); |
| 499 | QSGHiQSubPixelDistanceFieldTextMaterial *oldMat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(oldMaterial); |
| 500 | |
| 501 | QByteArray *buf = state.uniformData(); |
| 502 | Q_ASSERT(buf->size() >= 128); |
| 503 | |
| 504 | if (!oldMat || mat->fontScale() != oldMat->fontScale()) { |
| 505 | float fontScale = mat->fontScale(); |
| 506 | memcpy(dest: buf->data() + m_currentUbufOffset, src: &fontScale, n: 4); |
| 507 | changed = true; |
| 508 | } |
| 509 | m_currentUbufOffset += 4 + 4; // 4 for padding for vec2 alignment |
| 510 | |
| 511 | if (!oldMat || state.isMatrixDirty()) { |
| 512 | int viewportWidth = state.viewportRect().width(); |
| 513 | QMatrix4x4 mat = state.combinedMatrix().inverted(); |
| 514 | QVector4D vecDelta = mat.column(index: 0) * (qreal(2) / viewportWidth); |
| 515 | memcpy(dest: buf->data() + m_currentUbufOffset, src: &vecDelta, n: 16); |
| 516 | } |
| 517 | |
| 518 | return changed; |
| 519 | } |
| 520 | |
| 521 | bool QSGHiQSubPixelDistanceFieldTextMaterialRhiShader::updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps, |
| 522 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
| 523 | { |
| 524 | Q_UNUSED(state); |
| 525 | Q_UNUSED(oldMaterial); |
| 526 | QSGHiQSubPixelDistanceFieldTextMaterial *mat = static_cast<QSGHiQSubPixelDistanceFieldTextMaterial *>(newMaterial); |
| 527 | |
| 528 | ps->blendEnable = true; |
| 529 | ps->srcColor = GraphicsPipelineState::ConstantColor; |
| 530 | ps->dstColor = GraphicsPipelineState::OneMinusSrcColor; |
| 531 | |
| 532 | const QVector4D color = mat->color(); |
| 533 | // this is dynamic state but it's - magic! - taken care of by the renderer |
| 534 | ps->blendConstant = QColor::fromRgbF(r: color.x(), g: color.y(), b: color.z(), a: 1.0f); |
| 535 | |
| 536 | return true; |
| 537 | } |
| 538 | |
| 539 | QSGMaterialType *QSGHiQSubPixelDistanceFieldTextMaterial::type() const |
| 540 | { |
| 541 | static QSGMaterialType type; |
| 542 | return &type; |
| 543 | } |
| 544 | |
| 545 | QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
| 546 | { |
| 547 | if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported()) |
| 548 | return new DistanceFieldAnisotropicTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 549 | else |
| 550 | return new QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 551 | } |
| 552 | |
| 553 | class QSGLoQSubPixelDistanceFieldTextMaterialRhiShader : public QSGHiQSubPixelDistanceFieldTextMaterialRhiShader |
| 554 | { |
| 555 | public: |
| 556 | QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount); |
| 557 | }; |
| 558 | |
| 559 | QSGLoQSubPixelDistanceFieldTextMaterialRhiShader::QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(bool alphaTexture, int viewCount) |
| 560 | : QSGHiQSubPixelDistanceFieldTextMaterialRhiShader(alphaTexture, viewCount) |
| 561 | { |
| 562 | setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.vert.qsb" ), viewCount); |
| 563 | if (alphaTexture) |
| 564 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/loqsubpixeldistancefieldtext_a.frag.qsb" ), viewCount); |
| 565 | else |
| 566 | setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/loqsubpixeldistancefieldtext.frag.qsb" ), viewCount); |
| 567 | } |
| 568 | |
| 569 | QSGMaterialType *QSGLoQSubPixelDistanceFieldTextMaterial::type() const |
| 570 | { |
| 571 | static QSGMaterialType type; |
| 572 | return &type; |
| 573 | } |
| 574 | |
| 575 | QSGMaterialShader *QSGLoQSubPixelDistanceFieldTextMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const |
| 576 | { |
| 577 | if (renderMode == QSGRendererInterface::RenderMode3D && m_glyph_cache->screenSpaceDerivativesSupported()) |
| 578 | return new DistanceFieldAnisotropicTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 579 | else |
| 580 | return new QSGLoQSubPixelDistanceFieldTextMaterialRhiShader(m_glyph_cache->eightBitFormatIsAlphaSwizzled(), viewCount()); |
| 581 | } |
| 582 | |
| 583 | QT_END_NAMESPACE |
| 584 | |