Add support for accelerated glyph rendering in the directfb plugin

Change-Id: I44ae087c900e5cffdada45845cb7f34aab89b8ab
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Simon Hausmann 2014-08-13 16:33:27 +02:00
parent c8e7fe7f35
commit 258d35ceb3
5 changed files with 189 additions and 1 deletions

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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<QDirectFbTextureGlyphCache *>(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<DFBRectangle, 64> sourceRects(numGlyphs);
QVarLengthArray<DFBPoint, 64> destPoints(numGlyphs);
int nGlyphs = 0;
for (int i=0; i<numGlyphs; ++i) {
QFixed subPixelPosition = fontEngine->subPixelPositionForX(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<const QRasterPaintEngineState*>(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<void*>(static_cast<const void*>(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

View File

@ -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<IDirectFBSurface> m_surface;
};
QT_END_NAMESPACE
#endif // QDIRECTFBBLITTER_H