Skip to content

Commit

Permalink
Refactor lockedAlphaMapForGlyph
Browse files Browse the repository at this point in the history
Simply return a Glyph pointer and not a QImage to avoid allocating and
deleting lots of d pointers for QImage when drawing text. Saves one
new/delete pair per glyph drawn and speeds up text drawing by 10% for
relatively large glyphs (probably more for smaller ones).

The qtext::paintLayoutToPixmap() benchmark shows a 16% improvement
in performance with this change.

Renamed the method to glyphData().

Change-Id: I7a353de521e4f4321c770fb1ac6043d33f6f332c
Reviewed-by: Eskil Abrahamsen Blomfeldt <[email protected]>
  • Loading branch information
laknoll committed Aug 8, 2019
1 parent 6ac610c commit afb326f
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 91 deletions.
35 changes: 25 additions & 10 deletions src/gui/painting/qpaintengine_raster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2908,19 +2908,34 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
for (int i = 0; i < numGlyphs; i++) {
QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);

QPoint offset;
const QImage *alphaMap = fontEngine->lockedAlphaMapForGlyph(glyphs[i], spp, neededFormat, s->matrix,
&offset);
if (alphaMap == 0 || alphaMap->isNull())
const QFontEngine::Glyph *alphaMap = fontEngine->glyphData(glyphs[i], spp, neededFormat, s->matrix);
if (!alphaMap)
continue;

alphaPenBlt(alphaMap->constBits(), alphaMap->bytesPerLine(), alphaMap->depth(),
qFloor(positions[i].x) + offset.x(),
qRound(positions[i].y) + offset.y(),
alphaMap->width(), alphaMap->height(),
int depth;
int bytesPerLine;
switch (alphaMap->format) {
case QFontEngine::Format_Mono:
depth = 1;
bytesPerLine = ((alphaMap->width + 31) & ~31) >> 3;
break;
case QFontEngine::Format_A8:
depth = 8;
bytesPerLine = (alphaMap->width + 3) & ~3;
break;
case QFontEngine::Format_A32:
depth = 32;
bytesPerLine = alphaMap->width * 4;
break;
default:
Q_UNREACHABLE();
};

alphaPenBlt(alphaMap->data, bytesPerLine, depth,
qFloor(positions[i].x) + alphaMap->x,
qRound(positions[i].y) - alphaMap->y,
alphaMap->width, alphaMap->height,
fontEngine->expectsGammaCorrectedBlending());

fontEngine->unlockAlphaMapForGlyph();
}

} else {
Expand Down
25 changes: 3 additions & 22 deletions src/gui/text/qfontengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -923,29 +923,10 @@ QFixed QFontEngine::subPixelPositionForX(QFixed x) const
return subPixelPosition;
}

QImage *QFontEngine::lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
QFontEngine::GlyphFormat neededFormat,
const QTransform &t, QPoint *offset)
QFontEngine::Glyph *QFontEngine::glyphData(glyph_t, QFixed,
QFontEngine::GlyphFormat, const QTransform &)
{
Q_ASSERT(currentlyLockedAlphaMap.isNull());
if (neededFormat == Format_None)
neededFormat = Format_A32;

if (neededFormat != Format_A32)
currentlyLockedAlphaMap = alphaMapForGlyph(glyph, subPixelPosition, t);
else
currentlyLockedAlphaMap = alphaRGBMapForGlyph(glyph, subPixelPosition, t);

if (offset != 0)
*offset = QPoint(0, 0);

return &currentlyLockedAlphaMap;
}

void QFontEngine::unlockAlphaMapForGlyph()
{
Q_ASSERT(!currentlyLockedAlphaMap.isNull());
currentlyLockedAlphaMap = QImage();
return nullptr;
}

QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
Expand Down
23 changes: 17 additions & 6 deletions src/gui/text/qfontengine_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,22 @@ class Q_GUI_EXPORT QFontEngine
};
Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)

/* Used with the Freetype font engine. We don't cache glyphs that are too large anyway, so we can make this struct rather small */
struct Glyph {
Glyph() = default;
~Glyph() { delete [] data; }
short linearAdvance = 0;
unsigned char width = 0;
unsigned char height = 0;
short x = 0;
short y = 0;
short advance = 0;
signed char format = 0;
uchar *data = nullptr;
private:
Q_DISABLE_COPY(Glyph);
};

virtual ~QFontEngine();

inline Type type() const { return m_type; }
Expand Down Expand Up @@ -191,11 +207,7 @@ class Q_GUI_EXPORT QFontEngine
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
virtual QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color = QColor());
virtual QImage *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
GlyphFormat neededFormat,
const QTransform &t = QTransform(),
QPoint *offset = 0);
virtual void unlockAlphaMapForGlyph();
virtual Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition, GlyphFormat neededFormat, const QTransform &t);
virtual bool hasInternalCaching() const { return false; }

virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/)
Expand Down Expand Up @@ -346,7 +358,6 @@ class Q_GUI_EXPORT QFontEngine
void loadKerningPairs(QFixed scalingFactor);

GlyphFormat glyphFormat;
QImage currentlyLockedAlphaMap;
int m_subPixelPositionCount; // Number of positions within a single pixel for this cache

inline QVariant userData() const { return m_userData; }
Expand Down
41 changes: 6 additions & 35 deletions src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *leng
return result;
}

static QFontEngineFT::Glyph emptyGlyph = {0, 0, 0, 0, 0, 0, 0, 0};
static QFontEngineFT::Glyph emptyGlyph;

static const QFontEngine::HintStyle ftInitialDefaultHintStyle =
#ifdef Q_OS_WIN
Expand Down Expand Up @@ -556,11 +556,6 @@ void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point,
slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
}

QFontEngineFT::Glyph::~Glyph()
{
delete [] data;
}

struct LcdFilterDummy
{
static inline void filterPixel(uchar &, uchar &, uchar &)
Expand Down Expand Up @@ -1986,11 +1981,10 @@ static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEng
return img;
}

QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
QFontEngine::GlyphFormat neededFormat,
const QTransform &t, QPoint *offset)
QFontEngine::Glyph *QFontEngineFT::glyphData(glyph_t glyphIndex, QFixed subPixelPosition,
QFontEngine::GlyphFormat neededFormat, const QTransform &t)
{
Q_ASSERT(currentlyLockedAlphaMap.isNull());
Q_ASSERT(cacheEnabled);

if (isBitmapFont())
neededFormat = Format_Mono;
Expand All @@ -2000,33 +1994,10 @@ QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixe
neededFormat = Format_A8;

Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t);

if (offset != 0 && glyph != 0)
*offset = QPoint(glyph->x, -glyph->y);

currentlyLockedAlphaMap = alphaMapFromGlyphData(glyph, neededFormat);

const bool glyphHasGeometry = glyph != nullptr && glyph->height != 0 && glyph->width != 0;
if (!cacheEnabled && glyph != &emptyGlyph) {
currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy();
delete glyph;
}

if (!glyphHasGeometry)
if (!glyph || !glyph->width || !glyph->height)
return nullptr;

if (currentlyLockedAlphaMap.isNull())
return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t, offset);

QImageData *data = currentlyLockedAlphaMap.data_ptr();
data->is_locked = true;

return &currentlyLockedAlphaMap;
}

void QFontEngineFT::unlockAlphaMapForGlyph()
{
QFontEngine::unlockAlphaMapForGlyph();
return glyph;
}

static inline bool is2dRotation(const QTransform &t)
Expand Down
20 changes: 2 additions & 18 deletions src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,6 @@ class QFreetypeFace
class QFontEngineFT : public QFontEngine
{
public:

/* we don't cache glyphs that are too large anyway, so we can make this struct rather small */
struct Glyph {
~Glyph();
int linearAdvance : 22;
unsigned char width;
unsigned char height;
short x;
short y;
short advance;
signed char format;
uchar *data;
};

struct GlyphInfo {
int linearAdvance;
unsigned short width;
Expand Down Expand Up @@ -241,11 +227,9 @@ class QFontEngineFT : public QFontEngine
QFixed subPixelPosition,
const QTransform &matrix,
QFontEngine::GlyphFormat format) override;
QImage *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
GlyphFormat neededFormat, const QTransform &t,
QPoint *offset) override;
Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition,
GlyphFormat neededFormat, const QTransform &t) override;
bool hasInternalCaching() const override { return cacheEnabled; }
void unlockAlphaMapForGlyph() override;
bool expectsGammaCorrectedBlending() const override;

void removeGlyphFromCache(glyph_t glyph) override;
Expand Down

0 comments on commit afb326f

Please sign in to comment.