7#include <QtGui/private/qdistancefield_p.h>
8#include <QtCore/qelapsedtimer.h>
9#include <QtQml/private/qqmlglobal_p.h>
18#if !defined(QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING)
19# define QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING 2
24 int renderTypeQuality)
30 loadPregeneratedCache(
font);
35 for (
const TextureInfo &
t : std::as_const(m_textures))
38 delete m_areaAllocator;
46 if (m_areaAllocator ==
nullptr)
56 QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2);
69 unusedCoord.
y - padding,
70 padding * 2 + unusedGlyphWidth,
71 padding * 2 + unusedGlyphHeight));
73 m_unusedGlyphs.
remove(unusedGlyph);
74 m_glyphsTexture.
remove(unusedGlyph);
77 alloc = m_areaAllocator->
allocate(glyphSize);
88 tex->allocatedArea |= alloc;
89 Q_ASSERT(tex->padding == padding || tex->padding < 0);
90 tex->padding = padding;
97 glyphsToRender.
append(glyphIndex);
98 m_glyphsTexture.
insert(glyphIndex, tex);
107 return !m_referencedGlyphs.
empty();
113 typedef GlyphTextureHash::const_iterator GlyphTextureHashConstIt;
115 GlyphTextureHash glyphTextures;
118 for (
int i = 0;
i < glyphs.
size(); ++
i) {
122 TextureInfo *texInfo = m_glyphsTexture.
value(glyphIndex);
124 resizeTexture(texInfo, texInfo->allocatedArea.width(), texInfo->allocatedArea.height());
126 glyphTextures[texInfo].append(glyphIndex);
128 int padding = texInfo->padding;
129 int expectedWidth =
qCeil(
c.width +
c.xMargin * 2);
130 glyph = glyph.
copy(-padding, -padding,
131 expectedWidth + padding * 2, glyph.
height() + padding * 2);
135 uchar *outBits = texInfo->image.scanLine(
int(
c.y) - padding) + int(
c.x) - padding;
136 for (
int y = 0;
y < glyph.
height(); ++
y) {
137 memcpy(outBits, inBits, glyph.
width());
138 inBits += glyph.
width();
139 outBits += texInfo->image.width();
150 for (
int i = 0;
i < glyphs.
size(); ++
i) {
151 TextureInfo *texInfo = m_glyphsTexture.
value(glyphs.
at(
i).glyph());
152 if (!texInfo->uploads.isEmpty()) {
154 desc.setEntries(texInfo->uploads.cbegin(), texInfo->uploads.cend());
156 texInfo->uploads.clear();
160 for (GlyphTextureHashConstIt
i = glyphTextures.constBegin(), cend = glyphTextures.constEnd();
i != cend; ++
i) {
162 t.texture =
i.key()->texture;
163 t.size =
i.key()->size;
170 m_referencedGlyphs += glyphs;
171 m_unusedGlyphs -= glyphs;
176 m_referencedGlyphs -= glyphs;
177 m_unusedGlyphs += glyphs;
180void QSGRhiDistanceFieldGlyphCache::createTexture(
TextureInfo *texInfo,
185 createTexture(texInfo,
width,
height, zeroBuf.constData());
188void QSGRhiDistanceFieldGlyphCache::createTexture(
TextureInfo *texInfo,
199 if (texInfo->texture->create()) {
205 qWarning(
"Failed to create distance field glyph cache");
213 int oldWidth = texInfo->size.width();
214 int oldHeight = texInfo->size.height();
229 oldWidth * oldHeight);
230 subresDesc.setSourceSize(
QSize(oldWidth, oldHeight));
232 texInfo->image = texInfo->image.copy(0, 0,
width,
height);
234 resourceUpdates->
copyTexture(texInfo->texture, oldTexture);
242 static bool set =
false;
243 static bool useWorkaround =
false;
248 return useWorkaround;
258 if (!m_maxTextureSize)
260 return m_maxTextureSize;
270 GlyphRecordSize = 46,
271 TextureRecordSize = 17
294 boundingRectWidth = 36,
295 boundingRectHeight = 40,
302 allocatedHeight = 12,
307 template <
typename T>
315bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(
const QRawFont &
font)
319 if (m_areaAllocator !=
nullptr) {
320 qWarning(
"Font cache must be loaded before cache is used");
326 bool profile = QSG_LOG_TIME_GLYPH().isDebugEnabled();
336 GlyphTextureHash glyphTextures;
338 if (
uint(qtdfTable.
size()) < Qtdf::HeaderSize) {
339 qWarning(
"Invalid qtdf table in font '%s'",
344 const char *qtdfTableStart = qtdfTable.
constData();
345 const char *qtdfTableEnd = qtdfTableStart + qtdfTable.
size();
348 int textureCount = 0;
350 quint8 majorVersion = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::majorVersion);
351 quint8 minorVersion = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::minorVersion);
352 if (majorVersion != 5 || minorVersion != 12) {
353 qWarning(
"Invalid version of qtdf table %d.%d in font '%s'",
360 qreal pixelSize =
qreal(Qtdf::fetch<quint16>(qtdfTableStart, Qtdf::pixelSize));
361 m_maxTextureSize = Qtdf::fetch<quint32>(qtdfTableStart, Qtdf::textureSize);
363 padding = Qtdf::fetch<quint8>(qtdfTableStart, Qtdf::headerPadding);
365 if (pixelSize <= 0.0) {
370 if (m_maxTextureSize <= 0) {
377 if (m_maxTextureSize > systemMaxTextureSize) {
378 qWarning(
"System maximum texture size is %d. This is lower than the value in '%s', which is %d",
379 systemMaxTextureSize,
385 qWarning(
"Padding mismatch in '%s'. Font requires %d, but Qt is compiled with %d.",
396 const char *allocatorData = qtdfTableStart + Qtdf::HeaderSize;
399 allocatorData = m_areaAllocator->
deserialize(allocatorData, qtdfTableEnd - allocatorData);
400 if (allocatorData ==
nullptr)
404 if (m_areaAllocator->
size().
height() % m_maxTextureSize != 0) {
409 textureCount = m_areaAllocator->
size().
height() / m_maxTextureSize;
410 m_maxTextureCount =
qMax(m_maxTextureCount, textureCount);
412 const char *textureRecord = allocatorData;
413 for (
int i = 0;
i < textureCount; ++
i, textureRecord += Qtdf::TextureRecordSize) {
414 if (qtdfTableEnd - textureRecord < Qtdf::TextureRecordSize) {
415 qWarning(
"qtdf table too small in font '%s'.",
421 tex->allocatedArea.setX(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedX));
422 tex->allocatedArea.setY(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedY));
423 tex->allocatedArea.setWidth(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedWidth));
424 tex->allocatedArea.setHeight(Qtdf::fetch<quint32>(textureRecord, Qtdf::allocatedHeight));
425 tex->padding = Qtdf::fetch<quint8>(textureRecord, Qtdf::texturePadding);
428 const char *glyphRecord = textureRecord;
430 if (qtdfTableEnd - glyphRecord < Qtdf:: GlyphRecordSize) {
431 qWarning(
"qtdf table too small in font '%s'.",
436 glyph_t glyph = Qtdf::fetch<quint32>(glyphRecord, Qtdf::glyphIndex);
437 m_unusedGlyphs.
insert(glyph);
441#define FROM_FIXED_POINT(value) \
442(((qreal)value)/(qreal)65536)
455#undef FROM_FIXED_POINT
457 int textureIndex = Qtdf::fetch<quint16>(glyphRecord, Qtdf::textureIndex);
458 if (textureIndex < 0 || textureIndex >= textureCount) {
459 qWarning(
"Invalid texture index %d (texture count == %d) in '%s'",
468 m_glyphsTexture.
insert(glyph, texInfo);
470 glyphTextures[texInfo].append(glyph);
473 const uchar *textureData =
reinterpret_cast<const uchar *
>(glyphRecord);
474 for (
int i = 0;
i < textureCount; ++
i) {
478 int width = texInfo->allocatedArea.width();
479 int height = texInfo->allocatedArea.height();
481 if (qtdfTableEnd -
reinterpret_cast<const char *
>(textureData) <
size) {
482 qWarning(
"qtdf table too small in font '%s'.",
487 createTexture(texInfo,
width,
height, textureData);
492 t.texture = texInfo->texture;
493 t.size = texInfo->size;
504 "distancefield: %d pre-generated glyphs loaded in %dms",
505 int(m_unusedGlyphs.
size()),
515 mergeInto->
merge(resourceUpdates);
532#if defined(QSG_DISTANCEFIELD_CACHE_DEBUG)
545 if (numPixels == rbResult->
data.
size()) {
549 for (
int i = 0;
i <
size.height();
i++)
552 }
else if (4 * numPixels == rbResult->
data.
size()) {
558 qWarning(
"Unhandled data format in glyph texture");
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
QDistanceField copy(const QRect &rect=QRect()) const
const uchar * constBits() const
bool remove(const Key &key)
Removes the item that has the key from the hash.
T value(const Key &key) const noexcept
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
qsizetype size() const noexcept
const_reference at(qsizetype i) const noexcept
T value(qsizetype i) const
void append(parameter_type t)
\inmodule QtCore\reentrant
The QRawFont class provides access to a single physical instance of a font.
void setPixelSize(qreal pixelSize)
Sets the pixel size with which this font should be rendered to pixelSize.
\inmodule QtCore\reentrant
constexpr qreal height() const noexcept
Returns the height of the rectangle.
constexpr qreal width() const noexcept
Returns the width of the rectangle.
constexpr void setY(qreal pos) noexcept
Sets the top edge of the rectangle to the given finite y coordinate.
constexpr void setWidth(qreal w) noexcept
Sets the width of the rectangle to the given finite width.
constexpr void setHeight(qreal h) noexcept
Sets the height of the rectangle to the given finite height.
constexpr void setX(qreal pos) noexcept
Sets the left edge of the rectangle to the given finite x coordinate.
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr bool isNull() const noexcept
Returns true if the rectangle is a null rectangle, otherwise returns false.
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
void merge(QRhiResourceUpdateBatch *other)
Copies all queued operations from the other batch into this one.
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
Enqueues uploading the image data for one or more mip levels in one or more layers of the texture tex...
void readBackTexture(const QRhiReadbackDescription &rb, QRhiReadbackResult *result)
Enqueues a texture-to-host copy operation as described by rb.
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc=QRhiTextureCopyDescription())
Enqueues a texture-to-texture copy operation from src into dst as described by desc.
void setDestinationTopLeft(const QPoint &p)
Sets the destination top-left position p.
void setSourceSize(const QSize &size)
Sets the source size in pixels.
int resourceLimit(ResourceLimit limit) const
bool isFeatureSupported(QRhi::Feature feature) const
Implementation backend() const
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
const char * deserialize(const char *data, int size)
QRect allocate(const QSize &size)
bool deallocate(const QRect &rect)
void deferredReleaseGlyphCacheTexture(QRhiTexture *texture)
QRhiResourceUpdateBatch * maybeGlyphCacheResourceUpdates()
void resetGlyphCacheResources()
QRhiResourceUpdateBatch * glyphCacheResourceUpdates()
qreal distanceFieldRadius() const
void markGlyphsToRender(const QVector< glyph_t > &glyphs)
GlyphData & emptyData(glyph_t glyph)
void setGlyphsTexture(const QVector< glyph_t > &glyphs, const Texture &tex)
void setGlyphsPosition(const QList< GlyphPosition > &glyphs)
TexCoord glyphTexCoord(glyph_t glyph)
bool m_doubleGlyphResolution
void updateRhiTexture(QRhiTexture *oldTex, QRhiTexture *newTex, const QSize &newTexSize)
GlyphData & glyphData(glyph_t glyph)
void removeGlyph(glyph_t glyph)
void releaseGlyphs(const QSet< glyph_t > &glyphs) override
bool useTextureResizeWorkaround() const
void referenceGlyphs(const QSet< glyph_t > &glyphs) override
void commitResourceUpdates(QRhiResourceUpdateBatch *mergeInto)
void storeGlyphs(const QList< QDistanceField > &glyphs) override
virtual ~QSGRhiDistanceFieldGlyphCache()
bool eightBitFormatIsAlphaSwizzled() const override
void requestGlyphs(const QSet< glyph_t > &glyphs) override
bool screenSpaceDerivativesSupported() const override
bool createFullSizeTextures() const
int maxTextureSize() const
bool isActive() const override
QSGRhiDistanceFieldGlyphCache(QSGDefaultRenderContext *rc, const QRawFont &font, int renderTypeQuality)
bool remove(const T &value)
const_iterator constBegin() const noexcept
const_iterator constEnd() const noexcept
void reserve(qsizetype size)
iterator insert(const T &value)
constexpr int height() const noexcept
Returns the height.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
int QT_DISTANCEFIELD_HIGHGLYPHCOUNT()
#define qCDebug(category,...)
constexpr const T & qMax(const T &a, const T &b)
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum const void GLbitfield GLsizei numGlyphs
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum const void * pixels
static const QRectF boundingRect(const QPointF *points, int pointCount)
#define DEFINE_BOOL_CONFIG_OPTION(name, var)
#define QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING
#define FROM_FIXED_POINT(value)
#define qPrintable(string)
QLatin1StringView QLatin1String
unsigned long long quint64
QFuture< QSet< QChar > > set
[10]
\inmodule QtCore \reentrant
std::function< void()> completed