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