From 258d35ceb3142d654d02799516c433ccf7094313 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Wed, 13 Aug 2014 16:33:27 +0200 Subject: [PATCH] Add support for accelerated glyph rendering in the directfb plugin Change-Id: I44ae087c900e5cffdada45845cb7f34aab89b8ab Reviewed-by: Lars Knoll --- src/gui/painting/qblittable_p.h | 14 ++ src/gui/painting/qpaintengine_blitter.cpp | 35 +++++ src/gui/painting/qpaintengine_blitter_p.h | 1 + .../platforms/directfb/qdirectfbblitter.cpp | 124 +++++++++++++++++- .../platforms/directfb/qdirectfbblitter.h | 16 +++ 5 files changed, 189 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qblittable_p.h b/src/gui/painting/qblittable_p.h index f65549d63c..0f846741b3 100644 --- a/src/gui/painting/qblittable_p.h +++ b/src/gui/painting/qblittable_p.h @@ -64,6 +64,9 @@ public: SourceOverScaledPixmapCapability = 0x0008, AlphaFillRectCapability = 0x0010, OpacityPixmapCapability = 0x0020, + DrawScaledCachedGlyphsCapability = 0x0040, + SubPixelGlyphsCapability = 0x0080, + ComplexClipCapability = 0x0100, // Internal ones OutlineCapability = 0x0001000 @@ -92,6 +95,17 @@ public: Q_UNUSED(opacity); qWarning("Please implement drawPixmapOpacity function in your platform or remove OpacityPixmapCapability from it"); } + virtual bool drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) { + Q_UNUSED(state); + Q_UNUSED(glyphFormat); + Q_UNUSED(numGlyphs); + Q_UNUSED(glyphs); + Q_UNUSED(positions); + Q_UNUSED(fontEngine); + qWarning("Please implement drawCachedGlyphs function in your platform or remove DrawCachedGlyphsCapability from it"); + return true; + } + QImage *lock(); void unlock(); diff --git a/src/gui/painting/qpaintengine_blitter.cpp b/src/gui/painting/qpaintengine_blitter.cpp index 67a692e2db..9a3b8f421b 100644 --- a/src/gui/painting/qpaintengine_blitter.cpp +++ b/src/gui/painting/qpaintengine_blitter.cpp @@ -132,6 +132,19 @@ public: return checkStateAgainstMask(capabillitiesState, opacityPixmapMask); } + bool canBlitterDrawCachedGlyphs(const QTransform &transform, QFontEngine::GlyphFormat requestedGlyphFormat, bool complexClip) const + { + if (transform.type() > QTransform::TxScale) + return false; + if (!(m_capabilities & QBlittable::DrawScaledCachedGlyphsCapability)) + return false; + if (requestedGlyphFormat == QFontEngine::Format_ARGB && !(m_capabilities & QBlittable::SubPixelGlyphsCapability)) + return false; + if (complexClip && !(m_capabilities & QBlittable::ComplexClipCapability)) + return false; + return true; + } + inline void updateState(uint mask, bool on) { updateStateBits(&capabillitiesState, mask, on); } @@ -798,6 +811,28 @@ void QBlitterPaintEngine::drawStaticTextItem(QStaticTextItem *sti) #endif } +bool QBlitterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) +{ + Q_D(QBlitterPaintEngine); + QFontEngine::GlyphFormat glyphFormat = d->glyphCacheFormat; + if (fontEngine->glyphFormat != QFontEngine::Format_None) + glyphFormat = fontEngine->glyphFormat; + + const QClipData *clipData = d->clip(); + const bool complexClip = clipData && !clipData->hasRectClip; + + const QPainterState *s = state(); + if (d->caps.canBlitterDrawCachedGlyphs(s->transform(), glyphFormat, complexClip)) { + d->unlock(); + const bool result = d->pmData->blittable()->drawCachedGlyphs(s, glyphFormat, numGlyphs, glyphs, positions, fontEngine); + // Lock again as the raster paint engine might draw decorations now. + d->lock(); + return result; + } else { + return QRasterPaintEngine::drawCachedGlyphs(numGlyphs, glyphs, positions, fontEngine); + } +} + QT_END_NAMESPACE #endif //QT_NO_BLITTABLE diff --git a/src/gui/painting/qpaintengine_blitter_p.h b/src/gui/painting/qpaintengine_blitter_p.h index b70ee5fc5c..56661a7d90 100644 --- a/src/gui/painting/qpaintengine_blitter_p.h +++ b/src/gui/painting/qpaintengine_blitter_p.h @@ -96,6 +96,7 @@ public: void drawPoints(const QPoint *points, int pointCount); void stroke(const QVectorPath &path, const QPen &pen); void drawStaticTextItem(QStaticTextItem *); + bool drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.cpp b/src/plugins/platforms/directfb/qdirectfbblitter.cpp index 46f811f816..bc6e4d70e9 100644 --- a/src/plugins/platforms/directfb/qdirectfbblitter.cpp +++ b/src/plugins/platforms/directfb/qdirectfbblitter.cpp @@ -58,7 +58,9 @@ static QBlittable::Capabilities dfb_blitter_capabilities() |QBlittable::SourceOverPixmapCapability |QBlittable::SourceOverScaledPixmapCapability |QBlittable::AlphaFillRectCapability - |QBlittable::OpacityPixmapCapability); + |QBlittable::OpacityPixmapCapability + |QBlittable::DrawScaledCachedGlyphsCapability + ); } QDirectFbBlitter::QDirectFbBlitter(const QSize &rect, IDirectFBSurface *surface) @@ -210,6 +212,86 @@ void QDirectFbBlitter::drawPixmapOpacity(const QRectF &rect, const QPixmap &pixm DirectFBError("QDirectFBBlitter::drawPixmapExtended()", result); } +bool QDirectFbBlitter::drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine) +{ + void *cacheKey = QDirectFbConvenience::dfbInterface(); + + QDirectFbTextureGlyphCache *cache = + static_cast(fontEngine->glyphCache(cacheKey, glyphFormat, state->transform())); + if (!cache) { + cache = new QDirectFbTextureGlyphCache(glyphFormat, state->transform()); + fontEngine->setGlyphCache(cacheKey, cache); + } + + cache->populate(fontEngine, numGlyphs, glyphs, positions); + cache->fillInPendingGlyphs(); + + if (cache->image().width() == 0 || cache->image().height() == 0) + return false; + + const int margin = fontEngine->glyphMargin(glyphFormat); + + QVarLengthArray sourceRects(numGlyphs); + QVarLengthArray destPoints(numGlyphs); + int nGlyphs = 0; + + for (int i=0; isubPixelPositionForX(positions[i].x); + QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition); + const QTextureGlyphCache::Coord &c = cache->coords[glyph]; + if (c.isNull()) + continue; + + int x = qFloor(positions[i].x) + c.baseLineX - margin; + int y = qRound(positions[i].y) - c.baseLineY - margin; + + // printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n", + // c.x, c.y, + // c.w, c.h, + // c.baseLineX, c.baseLineY, + // glyphs[i], + // x, y, + // positions[i].x.toInt(), positions[i].y.toInt()); + + sourceRects[nGlyphs].x = c.x; + sourceRects[nGlyphs].y = c.y; + sourceRects[nGlyphs].w = c.w; + sourceRects[nGlyphs].h = c.h; + destPoints[nGlyphs].x = x; + destPoints[nGlyphs].y = y; + ++nGlyphs; + } + + const QColor color = state->pen().color(); + m_surface->SetColor(m_surface.data(), color.red(), color.green(), color.blue(), color.alpha()); + + m_surface->SetSrcBlendFunction(m_surface.data(), DSBF_SRCALPHA); + m_surface->SetDstBlendFunction(m_surface.data(), DSBF_INVSRCALPHA); + + int flags = DSBLIT_BLEND_ALPHACHANNEL | DSBLIT_COLORIZE; + if (color.alpha() != 0xff) + flags |= DSBLIT_BLEND_COLORALPHA; + m_surface->SetBlittingFlags(m_surface.data(), DFBSurfaceBlittingFlags(flags)); + + const QRasterPaintEngineState *rs = static_cast(state); + if (rs->clip && rs->clip->enabled) { + Q_ASSERT(rs->clip->hasRectClip); + DFBRegion dfbClip; + dfbClip.x1 = rs->clip->clipRect.x(); + dfbClip.y1 = rs->clip->clipRect.y(); + dfbClip.x2 = rs->clip->clipRect.right(); + dfbClip.y2 = rs->clip->clipRect.bottom(); + m_surface->SetClip(m_surface.data(), &dfbClip); + } + + m_surface->BatchBlit(m_surface.data(), cache->sourceSurface(), sourceRects.constData(), destPoints.constData(), nGlyphs); + + if (rs->clip && rs->clip->enabled) + m_surface->SetClip(m_surface.data(), 0); + return true; +} + QImage *QDirectFbBlitter::doLock() { Q_ASSERT(m_surface); @@ -321,4 +403,44 @@ void QDirectFbBlitter::doUnlock() m_surface->Unlock(m_surface.data()); } +void QDirectFbTextureGlyphCache::resizeTextureData(int width, int height) +{ + m_surface.reset();; + QImageTextureGlyphCache::resizeTextureData(width, height); +} + +IDirectFBSurface *QDirectFbTextureGlyphCache::sourceSurface() +{ + if (m_surface.isNull()) { + const QImage &source = image(); + DFBSurfaceDescription desc; + memset(&desc, 0, sizeof(desc)); + desc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT | DSDESC_PREALLOCATED | DSDESC_CAPS); + desc.width = source.width(); + desc.height = source.height(); + desc.caps = DSCAPS_SYSTEMONLY; + + switch (source.format()) { + case QImage::Format_Mono: + desc.pixelformat = DSPF_A1; + break; + case QImage::Format_Indexed8: + desc.pixelformat = DSPF_A8; + break; + default: + qFatal("QDirectFBTextureGlyphCache: Unsupported source texture image format."); + break; + } + + desc.preallocated[0].data = const_cast(static_cast(source.bits())); + desc.preallocated[0].pitch = source.bytesPerLine(); + desc.preallocated[1].data = 0; + desc.preallocated[1].pitch = 0; + + IDirectFB *dfb = QDirectFbConvenience::dfbInterface(); + dfb->CreateSurface(dfb , &desc, m_surface.outPtr()); + } + return m_surface.data(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/directfb/qdirectfbblitter.h b/src/plugins/platforms/directfb/qdirectfbblitter.h index 0255040729..c60f0fac25 100644 --- a/src/plugins/platforms/directfb/qdirectfbblitter.h +++ b/src/plugins/platforms/directfb/qdirectfbblitter.h @@ -61,6 +61,7 @@ public: virtual void drawPixmap(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect); void alphaFillRect(const QRectF &rect, const QColor &color, QPainter::CompositionMode cmode); void drawPixmapOpacity(const QRectF &rect, const QPixmap &pixmap, const QRectF &subrect, QPainter::CompositionMode cmode, qreal opacity); + virtual bool drawCachedGlyphs(const QPaintEngineState *state, QFontEngine::GlyphFormat glyphFormat, int numGlyphs, const glyph_t *glyphs, const QFixedPoint *positions, QFontEngine *fontEngine); IDirectFBSurface *dfbSurface() const; @@ -110,6 +111,21 @@ inline IDirectFBSurface *QDirectFbBlitter::dfbSurface() const return m_surface.data(); } +class QDirectFbTextureGlyphCache : public QImageTextureGlyphCache +{ +public: + QDirectFbTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix) + : QImageTextureGlyphCache(format, matrix) + {} + + virtual void resizeTextureData(int width, int height); + + IDirectFBSurface *sourceSurface(); + +private: + QDirectFBPointer m_surface; +}; + QT_END_NAMESPACE #endif // QDIRECTFBBLITTER_H