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