Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgrhitextureglyphcache.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
7#include <qrgb.h>
8#include <private/qdrawhelper_p.h>
9
11
14 const QColor &color)
15 : QImageTextureGlyphCache(format, matrix, color),
16 m_rc(rc),
17 m_rhi(rc->rhi())
18{
19 // Some OpenGL implementations, for instance macOS, have issues with
20 // GL_ALPHA render targets. Similarly, BGRA may be problematic on GLES 2.0.
21 // So stick with plain image uploads on GL.
22 m_resizeWithTextureCopy = m_rhi->backend() != QRhi::OpenGLES2;
23}
24
26{
27 m_rc->deferredReleaseGlyphCacheTexture(m_texture);
28}
29
30QRhiTexture *QSGRhiTextureGlyphCache::createEmptyTexture(QRhiTexture::Format format)
31{
32 QRhiTexture *t = m_rhi->newTexture(format, m_size, 1, QRhiTexture::UsedAsTransferSource);
33 if (!t->create()) {
34 qWarning("Failed to build new glyph cache texture of size %dx%d", m_size.width(), m_size.height());
35 return nullptr;
36 }
37
38 QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
39
40 // The new texture must be cleared to 0 always, this cannot be avoided
41 // otherwise artifacts will occur around the glyphs.
42 QByteArray data;
43 if (format == QRhiTexture::RED_OR_ALPHA8)
44 data.fill(0, m_size.width() * m_size.height());
45 else
46 data.fill(0, m_size.width() * m_size.height() * 4);
47 QRhiTextureSubresourceUploadDescription subresDesc(data.constData(), data.size());
48 subresDesc.setSourceSize(m_size);
49 resourceUpdates->uploadTexture(t, QRhiTextureUploadEntry(0, 0, subresDesc));
50
51 return t;
52}
53
54void QSGRhiTextureGlyphCache::createTextureData(int width, int height)
55{
56 width = qMax(128, width);
57 height = qMax(32, height);
58
59 if (!m_resizeWithTextureCopy)
60 QImageTextureGlyphCache::createTextureData(width, height);
61
62 m_size = QSize(width, height);
63}
64
65void QSGRhiTextureGlyphCache::resizeTextureData(int width, int height)
66{
67 width = qMax(128, width);
68 height = qMax(32, height);
69
70 if (m_size.width() >= width && m_size.height() >= height)
71 return;
72
73 m_size = QSize(width, height);
74
75 if (m_texture) {
76 QRhiTexture *t = createEmptyTexture(m_texture->format());
77 if (!t)
78 return;
79
80 QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
81 if (m_resizeWithTextureCopy) {
82 resourceUpdates->copyTexture(t, m_texture);
83 } else {
84 QImageTextureGlyphCache::resizeTextureData(width, height);
85 QImage img = image();
86 prepareGlyphImage(&img);
88 const QSize oldSize = m_texture->pixelSize();
89 subresDesc.setSourceSize(QSize(qMin(oldSize.width(), width), qMin(oldSize.height(), height)));
90 resourceUpdates->uploadTexture(t, QRhiTextureUploadEntry(0, 0, subresDesc));
91 }
92
93 m_rc->deferredReleaseGlyphCacheTexture(m_texture);
94 m_texture = t;
95 }
96}
97
99{
100 Q_ASSERT(m_uploads.isEmpty());
101}
102
103void QSGRhiTextureGlyphCache::prepareGlyphImage(QImage *img)
104{
105 const int maskWidth = img->width();
106 const int maskHeight = img->height();
107#if Q_BYTE_ORDER != Q_BIG_ENDIAN
108 const bool supportsBgra = m_rhi->isTextureFormatSupported(QRhiTexture::BGRA8);
109#endif
110 m_bgra = false;
111
112 if (img->format() == QImage::Format_Mono) {
113 *img = std::move(*img).convertToFormat(QImage::Format_Grayscale8);
114 } else if (img->format() == QImage::Format_RGB32 || img->format() == QImage::Format_ARGB32_Premultiplied) {
115 // We need to make the alpha component equal to the average of the RGB values.
116 // This is needed when drawing sub-pixel antialiased text on translucent targets.
117 if (img->format() == QImage::Format_RGB32
118#if Q_BYTE_ORDER != Q_BIG_ENDIAN
119 || !supportsBgra
120#endif
121 ) {
122 for (int y = 0; y < maskHeight; ++y) {
123 QRgb *src = reinterpret_cast<QRgb *>(img->scanLine(y));
124 for (int x = 0; x < maskWidth; ++x) {
125 QRgb &rgb = src[x];
126
127 if (img->format() == QImage::Format_RGB32) {
128 int r = qRed(rgb);
129 int g = qGreen(rgb);
130 int b = qBlue(rgb);
131 int avg = (r + g + b + 1) / 3; // "+1" for rounding.
132 rgb = qRgba(r, g, b, avg);
133 }
134
135#if Q_BYTE_ORDER != Q_BIG_ENDIAN
136 if (!supportsBgra) {
137 // swizzle the bits to accommodate for the RGBA upload.
138 rgb = ARGB2RGBA(rgb);
139 m_bgra = false;
140 }
141#endif
142 }
143 }
144 }
145#if Q_BYTE_ORDER != Q_BIG_ENDIAN
146 if (supportsBgra)
147 m_bgra = true;
148#endif
149 }
150}
151
152void QSGRhiTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, const QFixedPoint &subPixelPosition)
153{
155 QImage mask;
156
157 if (!m_resizeWithTextureCopy) {
158 QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition);
159 // Explicitly copy() here to avoid fillTexture detaching the *entire* image() when
160 // it is still referenced by QRhiTextureSubresourceUploadDescription.
161 mask = image().copy(QRect(c.x, c.y, c.w, c.h));
162 } else {
163 mask = textureMapForGlyph(glyph, subPixelPosition);
164 }
165
166 prepareGlyphImage(&mask);
167
168 subresDesc.setImage(mask);
169 subresDesc.setDestinationTopLeft(QPoint(c.x, c.y));
170 m_uploads.append(QRhiTextureUploadEntry(0, 0, subresDesc));
171}
172
174{
175 if (m_uploads.isEmpty())
176 return;
177
178 if (!m_texture) {
179 QRhiTexture::Format texFormat;
180 if (m_format == QFontEngine::Format_A32 || m_format == QFontEngine::Format_ARGB)
181 texFormat = m_bgra ? QRhiTexture::BGRA8 : QRhiTexture::RGBA8;
182 else // should be R8, but there is the OpenGL ES 2.0 nonsense
183 texFormat = QRhiTexture::RED_OR_ALPHA8;
184
185 m_texture = createEmptyTexture(texFormat);
186 if (!m_texture)
187 return;
188 }
189
190 QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
192 desc.setEntries(m_uploads.cbegin(), m_uploads.cend());
193 resourceUpdates->uploadTexture(m_texture, desc);
194 m_uploads.clear();
195}
196
198{
199 if (m_format == QFontEngine::Format_Mono)
200 return 8;
201 else
202 return 1;
203}
204
206{
207 return m_rhi->resourceLimit(QRhi::TextureSizeMax);
208}
209
211{
212 if (!m_resizeWithTextureCopy)
213 return qMin(1024, m_rhi->resourceLimit(QRhi::TextureSizeMax));
214
215 return m_rhi->resourceLimit(QRhi::TextureSizeMax);
216}
217
218void QSGRhiTextureGlyphCache::commitResourceUpdates(QRhiResourceUpdateBatch *mergeInto)
219{
220 if (QRhiResourceUpdateBatch *resourceUpdates = m_rc->maybeGlyphCacheResourceUpdates()) {
221 mergeInto->merge(resourceUpdates);
222 m_rc->resetGlyphCacheResources();
223 }
224}
225
227{
228 // return true when the shaders for 8-bit formats need .a instead of .r
229 // when sampling the texture
230 return !m_rhi->isFeatureSupported(QRhi::RedOrAlpha8IsRed);
231}
232
233QT_END_NAMESPACE
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:662
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:722
void resizeTextureData(int width, int height) override
void commitResourceUpdates(QRhiResourceUpdateBatch *mergeInto)
int maxTextureHeight() const override
void fillTexture(const Coord &c, glyph_t glyph, const QFixedPoint &subPixelPosition) override
void createTextureData(int width, int height) override
Combined button and popup list for selecting options.
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:14
constexpr int qRed(QRgb rgb)
Definition qrgb.h:19
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:22
constexpr QRgb qRgba(int r, int g, int b, int a)
Definition qrgb.h:34
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:25