diff options
Diffstat (limited to 'src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp')
-rw-r--r-- | src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp | 822 |
1 files changed, 401 insertions, 421 deletions
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index ade8554..94f1aeb 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -54,173 +54,22 @@ #include <private/qpixmapdata_p.h> #include <private/qpixmap_raster_p.h> -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define VOID_ARG() static_cast<bool>(false) -enum PaintOperation { - DRAW_RECTS = 0x0001, - DRAW_LINES = 0x0002, - DRAW_IMAGE = 0x0004, - DRAW_PIXMAP = 0x0008, - DRAW_TILED_PIXMAP = 0x0010, - STROKE_PATH = 0x0020, - DRAW_PATH = 0x0040, - DRAW_POINTS = 0x0080, - DRAW_ELLIPSE = 0x0100, - DRAW_POLYGON = 0x0200, - DRAW_TEXT = 0x0400, - FILL_PATH = 0x0800, - FILL_RECT = 0x1000, - DRAW_COLORSPANS = 0x2000, - ALL = 0xffff -}; -#endif - -#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS -template <typename T> inline const T *ptr(const T &t) { return &t; } -template <> inline const bool* ptr<bool>(const bool &) { return 0; } -template <typename device, typename T1, typename T2, typename T3> -static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, - int scale, bool matrixRotShear, bool simplePen, - bool dfbHandledClip, bool unsupportedCompositionMode, - const char *nameOne, const T1 &one, - const char *nameTwo, const T2 &two, - const char *nameThree, const T3 &three) -{ - QString out; - QDebug dbg(&out); - dbg << msg << (QByteArray(func) + "()") << "painting on"; - if (dev->devType() == QInternal::Widget) { - dbg << static_cast<const QWidget*>(dev); - } else { - dbg << dev << "of type" << dev->devType(); - } - - dbg << "scale" << scale - << "matrixRotShear" << matrixRotShear - << "simplePen" << simplePen - << "dfbHandledClip" << dfbHandledClip - << "unsupportedCompositionMode" << unsupportedCompositionMode; - - const T1 *t1 = ptr(one); - const T2 *t2 = ptr(two); - const T3 *t3 = ptr(three); - - if (t1) { - dbg << nameOne << *t1; - if (t2) { - dbg << nameTwo << *t2; - if (t3) { - dbg << nameThree << *t3; - } - } - } - qWarning("%s", qPrintable(out)); -} -#endif - -#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ - rasterFallbackWarn("Disabled raster engine operation", \ - __FUNCTION__, state()->painter->device(), \ - d_func()->scale, d_func()->matrixRotShear, \ - d_func()->simplePen, d_func()->dfbCanHandleClip(), \ - d_func()->unsupportedCompositionMode, \ - #one, one, #two, two, #three, three); \ - if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ - return; -#elif defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ - return; -#elif defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS -#define RASTERFALLBACK(op, one, two, three) \ - if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ - rasterFallbackWarn("Falling back to raster engine for", \ - __FUNCTION__, state()->painter->device(), \ - d_func()->scale, d_func()->matrixRotShear, \ - d_func()->simplePen, d_func()->dfbCanHandleClip(), \ - d_func()->unsupportedCompositionMode, \ - #one, one, #two, two, #three, three); -#else -#define RASTERFALLBACK(op, one, two, three) -#endif - -static inline uint ALPHA_MUL(uint x, uint a) -{ - uint t = x * a; - t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; - return t; -} - -class SurfaceCache -{ -public: - SurfaceCache() : surface(0), buffer(0), bufsize(0) {} - ~SurfaceCache() { clear(); } - - - IDirectFBSurface *getSurface(const uint *buf, int size) - { - if (buffer == buf && bufsize == size) - return surface; - - clear(); - - const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); - surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!surface) - qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); - - buffer = const_cast<uint*>(buf); - bufsize = size; - - return surface; - } - - void clear() - { - if (surface && QDirectFBScreen::instance()) - QDirectFBScreen::instance()->releaseDFBSurface(surface); - surface = 0; - buffer = 0; - bufsize = 0; - } -private: - IDirectFBSurface *surface; - uint *buffer; - int bufsize; -}; - - -#ifdef QT_DIRECTFB_IMAGECACHE -#include <private/qimage_p.h> -struct CachedImage -{ - IDirectFBSurface *surface; - ~CachedImage() - { - if (surface && QDirectFBScreen::instance()) { - QDirectFBScreen::instance()->releaseDFBSurface(surface); - } - } -}; -static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB -#endif - +class SurfaceCache; class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate { public: - enum Scale { NoScale, Scaled, NegativeScale }; - + enum TransformationTypeFlags { + NegativeScale = 0x100, + RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject), + BlitUnsupported = (NegativeScale|RectsUnsupported) + }; QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p); ~QDirectFBPaintEnginePrivate(); - void setTransform(const QTransform &m); - void setPen(const QPen &pen); + inline void setTransform(const QTransform &transforma); + inline void setPen(const QPen &pen); inline void setCompositionMode(QPainter::CompositionMode mode); - inline void setOpacity(quint8 value); - void setRenderHints(QPainter::RenderHints hints); + inline void setRenderHints(QPainter::RenderHints hints); inline void setDFBColor(const QColor &color); @@ -232,20 +81,11 @@ public: inline bool dfbCanHandleClip() const; inline bool isSimpleBrush(const QBrush &brush) const; - void drawLines(const QLine *lines, int count); - void drawLines(const QLineF *lines, int count); - - void fillRegion(const QRegion &r); - void fillRects(const QRect *rects, int count); - void drawRects(const QRect *rects, int count); - void fillRects(const QRectF *rects, int count); - void drawRects(const QRectF *rects, int count); - - void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap); + void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos); void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); inline void updateClip(); - void systemStateChanged(); + virtual void systemStateChanged(); static IDirectFBSurface *getSurface(const QImage &img, bool *release); @@ -257,22 +97,14 @@ public: private: IDirectFBSurface *surface; - QPen pen; - bool antialiased; - bool simplePen; - bool matrixRotShear; - Scale scale; + uint transformationType; // this is QTransform::type() + NegativeScale if qMin(transform.m11(), transform.m22()) < 0 SurfaceCache *surfaceCache; - QTransform transform; - int lastLockedHeight; IDirectFB *fb; - int fbWidth; - int fbHeight; quint8 opacity; @@ -280,13 +112,97 @@ private: bool dfbHandledClip; bool ignoreSystemClip; QDirectFBPaintDevice *dfbDevice; - void *lockedMemory; bool unsupportedCompositionMode; QDirectFBPaintEngine *q; + QRect currentClip; friend class QDirectFBPaintEngine; }; +class SurfaceCache +{ +public: + SurfaceCache() : surface(0), buffer(0), bufsize(0) {} + ~SurfaceCache() { clear(); } + IDirectFBSurface *getSurface(const uint *buf, int size); + void clear(); +private: + IDirectFBSurface *surface; + uint *buffer; + int bufsize; +}; + + +#ifdef QT_DIRECTFB_IMAGECACHE +#include <private/qimage_p.h> +struct CachedImage +{ + IDirectFBSurface *surface; + ~CachedImage() + { + if (surface && QDirectFBScreen::instance()) { + QDirectFBScreen::instance()->releaseDFBSurface(surface); + } + } +}; +static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB +#endif + +#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS || defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS +#define VOID_ARG() static_cast<bool>(false) +enum PaintOperation { + DRAW_RECTS = 0x0001, DRAW_LINES = 0x0002, DRAW_IMAGE = 0x0004, + DRAW_PIXMAP = 0x0008, DRAW_TILED_PIXMAP = 0x0010, STROKE_PATH = 0x0020, + DRAW_PATH = 0x0040, DRAW_POINTS = 0x0080, DRAW_ELLIPSE = 0x0100, + DRAW_POLYGON = 0x0200, DRAW_TEXT = 0x0400, FILL_PATH = 0x0800, + FILL_RECT = 0x1000, DRAW_COLORSPANS = 0x2000, ALL = 0xffff +}; +#endif + +#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS +template <typename device, typename T1, typename T2, typename T3> +static void rasterFallbackWarn(const char *msg, const char *, const device *, uint, bool, bool, bool, + const char *, const T1 &, const char *, const T2 &, const char *, const T3 &); +#endif + +#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS +#define RASTERFALLBACK(op, one, two, three) \ + if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ + rasterFallbackWarn("Disabled raster engine operation", \ + __FUNCTION__, state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->dfbCanHandleClip(), \ + d_func()->unsupportedCompositionMode, \ + #one, one, #two, two, #three, three); \ + if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ + return; +#elif defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS +#define RASTERFALLBACK(op, one, two, three) \ + if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \ + return; +#elif defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS +#define RASTERFALLBACK(op, one, two, three) \ + if (op & (QT_DIRECTFB_WARN_ON_RASTERFALLBACKS)) \ + rasterFallbackWarn("Falling back to raster engine for", \ + __FUNCTION__, state()->painter->device(), \ + d_func()->transformationType, \ + d_func()->simplePen, \ + d_func()->dfbCanHandleClip(), \ + d_func()->unsupportedCompositionMode, \ + #one, one, #two, two, #three, three); +#else +#define RASTERFALLBACK(op, one, two, three) +#endif + + +template <class T> +static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface); +template <class T> +static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); +template <class T> +static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface); + QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device) : QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device) { @@ -299,7 +215,6 @@ QDirectFBPaintEngine::~QDirectFBPaintEngine() bool QDirectFBPaintEngine::begin(QPaintDevice *device) { Q_D(QDirectFBPaintEngine); - d->lastLockedHeight = -1; if (device->devType() == QInternal::CustomRaster) { d->dfbDevice = static_cast<QDirectFBPaintDevice*>(device); } else if (device->devType() == QInternal::Pixmap) { @@ -316,23 +231,10 @@ bool QDirectFBPaintEngine::begin(QPaintDevice *device) qFatal("QDirectFBPaintEngine used on an invalid device: 0x%x", device->devType()); } - d->lockedMemory = 0; - - d->surface->GetSize(d->surface, &d->fbWidth, &d->fbHeight); - - d->setTransform(QTransform()); - d->antialiased = false; - d->setOpacity(255); - d->setCompositionMode(state()->compositionMode()); - d->dirtyClip = true; - d->setPen(state()->pen); - - const bool status = QRasterPaintEngine::begin(device); - // XXX: QRasterPaintEngine::begin() resets the capabilities - gccaps |= PorterDuff; + d->prepare(d->dfbDevice); - return status; + return QRasterPaintEngine::begin(device); } bool QDirectFBPaintEngine::end() @@ -343,6 +245,7 @@ bool QDirectFBPaintEngine::end() #if (Q_DIRECTFB_VERSION >= 0x010000) d->surface->ReleaseSource(d->surface); #endif + d->currentClip = QRect(); d->surface->SetClip(d->surface, NULL); d->surface = 0; return QRasterPaintEngine::end(); @@ -366,7 +269,7 @@ void QDirectFBPaintEngine::penChanged() void QDirectFBPaintEngine::opacityChanged() { Q_D(QDirectFBPaintEngine); - d->setOpacity(quint8(state()->opacity * 255)); + d->opacity = quint8(state()->opacity * 255); QRasterPaintEngine::opacityChanged(); } @@ -387,32 +290,26 @@ void QDirectFBPaintEngine::renderHintsChanged() void QDirectFBPaintEngine::transformChanged() { Q_D(QDirectFBPaintEngine); - const QDirectFBPaintEnginePrivate::Scale old = d->scale; - d->setTransform(state()->transform()); - if (d->scale != old) { - d->setPen(state()->pen); - } + d->setTransform(state()->matrix); QRasterPaintEngine::transformChanged(); } -void QDirectFBPaintEngine::setState(QPainterState *s) +void QDirectFBPaintEngine::setState(QPainterState *state) { Q_D(QDirectFBPaintEngine); - QRasterPaintEngine::setState(s); + QRasterPaintEngine::setState(state); d->dirtyClip = true; - d->setPen(state()->pen); - d->setOpacity(quint8(state()->opacity * 255)); - d->setCompositionMode(state()->compositionMode()); - d->setTransform(state()->transform()); + d->setPen(state->pen); + d->opacity = quint8(state->opacity * 255); + d->setCompositionMode(state->compositionMode()); + d->setTransform(state->transform()); + d->setRenderHints(state->renderHints); } void QDirectFBPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) { Q_D(QDirectFBPaintEngine); d->dirtyClip = true; - const QPoint bottom = d->transform.map(QPoint(0, int(path.controlPointRect().bottom()))); - if (bottom.y() > d->lastLockedHeight) - d->lock(); QRasterPaintEngine::clip(path, op); } @@ -420,12 +317,6 @@ void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) { Q_D(QDirectFBPaintEngine); d->dirtyClip = true; - if (d->clip() && !d->clip()->hasRectClip && d->clip()->enabled) { - const QPoint bottom = d->transform.map(QPoint(0, rect.bottom())); - if (bottom.y() > d->lastLockedHeight) - d->lock(); - } - QRasterPaintEngine::clip(rect, op); } @@ -434,8 +325,11 @@ void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) Q_D(QDirectFBPaintEngine); d->updateClip(); const QBrush &brush = state()->brush; - if (d->unsupportedCompositionMode || !d->dfbCanHandleClip() || d->matrixRotShear - || !d->simplePen || !d->isSimpleBrush(brush)) { + if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported) + || !d->simplePen + || !d->dfbCanHandleClip() + || !d->isSimpleBrush(brush)) { RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawRects(rects, rectCount); @@ -446,11 +340,12 @@ void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount) if (brush != Qt::NoBrush) { d->setDFBColor(brush.color()); - d->fillRects(rects, rectCount); + ::fillRects<QRect>(rects, rectCount, state()->matrix, d->surface); } - if (d->pen != Qt::NoPen) { - d->setDFBColor(d->pen.color()); - d->drawRects(rects, rectCount); + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { + d->setDFBColor(pen.color()); + ::drawRects<QRect>(rects, rectCount, state()->matrix, d->surface); } } @@ -459,8 +354,11 @@ void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) Q_D(QDirectFBPaintEngine); d->updateClip(); const QBrush &brush = state()->brush; - if (d->unsupportedCompositionMode || !d->dfbCanHandleClip() || d->matrixRotShear - || !d->simplePen || !d->isSimpleBrush(brush)) { + if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported) + || !d->simplePen + || !d->dfbCanHandleClip() + || !d->isSimpleBrush(brush)) { RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG()); d->lock(); QRasterPaintEngine::drawRects(rects, rectCount); @@ -471,11 +369,12 @@ void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount) if (brush != Qt::NoBrush) { d->setDFBColor(brush.color()); - d->fillRects(rects, rectCount); + ::fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface); } - if (d->pen != Qt::NoPen) { - d->setDFBColor(d->pen.color()); - d->drawRects(rects, rectCount); + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { + d->setDFBColor(pen.color()); + ::drawRects<QRectF>(rects, rectCount, state()->matrix, d->surface); } } @@ -490,10 +389,11 @@ void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount) return; } - if (d->pen != Qt::NoPen) { + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { d->unlock(); - d->setDFBColor(d->pen.color()); - d->drawLines(lines, lineCount); + d->setDFBColor(pen.color()); + ::drawLines<QLine>(lines, lineCount, state()->matrix, d->surface); } } @@ -508,10 +408,11 @@ void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount) return; } - if (d->pen != Qt::NoPen) { + const QPen &pen = state()->pen; + if (pen != Qt::NoPen) { d->unlock(); - d->setDFBColor(d->pen.color()); - d->drawLines(lines, lineCount); + d->setDFBColor(pen.color()); + ::drawLines<QLineF>(lines, lineCount, state()->matrix, d->surface); } } @@ -542,8 +443,7 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, d->updateClip(); #if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE if (d->unsupportedCompositionMode - || d->matrixRotShear - || d->scale == QDirectFBPaintEnginePrivate::NegativeScale + || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported) || !d->dfbCanHandleClip(r) #ifndef QT_DIRECTFB_IMAGECACHE || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN @@ -588,8 +488,9 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); d->lock(); QRasterPaintEngine::drawPixmap(r, pixmap, sr); - } else if (d->unsupportedCompositionMode || !d->dfbCanHandleClip(r) || d->matrixRotShear - || d->scale == QDirectFBPaintEnginePrivate::NegativeScale) { + } else if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported) + || !d->dfbCanHandleClip(r)) { RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr); const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ); d->lock(); @@ -613,30 +514,27 @@ void QDirectFBPaintEngine::drawPixmap(const QPointF &p, const QPixmap &pm) void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, - const QPointF &sp) + const QPointF &offset) { Q_D(QDirectFBPaintEngine); d->updateClip(); if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) { - RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), sp); + RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); d->lock(); - QRasterPaintEngine::drawTiledPixmap(r, pixmap, sp); - } else if (d->unsupportedCompositionMode || !d->dfbCanHandleClip(r) || d->matrixRotShear || !sp.isNull() - || d->scale == QDirectFBPaintEnginePrivate::NegativeScale) { - RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), sp); + QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset); + } else if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported) + || !d->dfbCanHandleClip(r)) { + RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset); const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ); d->lock(); QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType); data->fromImage(*img, Qt::AutoColor); const QPixmap pix(data); - QRasterPaintEngine::drawTiledPixmap(r, pix, sp); + QRasterPaintEngine::drawTiledPixmap(r, pix, offset); } else { d->unlock(); - QPixmapData *data = pixmap.pixmapData(); - Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); - QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); - dfbData->unlockDirectFB(); - d->drawTiledPixmap(r, pixmap); + d->drawTiledPixmap(r, pixmap, offset); } } @@ -721,7 +619,9 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) { Q_D(QDirectFBPaintEngine); d->updateClip(); - if (!d->unsupportedCompositionMode && d->dfbCanHandleClip(rect) && !d->matrixRotShear) { + if (!d->unsupportedCompositionMode + && !(d->transformationType & (QDirectFBPaintEnginePrivate::RectsUnsupported)) + && d->dfbCanHandleClip(rect)) { switch (brush.style()) { case Qt::SolidPattern: { const QColor color = brush.color(); @@ -729,18 +629,21 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) return; d->unlock(); d->setDFBColor(color); - const QRect r = d->transform.mapRect(rect).toRect(); + const QRect r = state()->matrix.mapRect(rect).toRect(); d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()); return; } - case Qt::TexturePattern: - if (state()->brushOrigin == QPointF() && brush.transform().isIdentity()) { - //could handle certain types of brush.transform() E.g. scale - d->unlock(); - d->drawTiledPixmap(rect, brush.texture()); - return; - } - break; + case Qt::TexturePattern: { + if (d->transformationType & QDirectFBPaintEnginePrivate::NegativeScale) + break; + + const QPixmap texture = brush.texture(); + if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass) + break; + + d->unlock(); + d->drawTiledPixmap(rect, texture, rect.topLeft() - state()->brushOrigin); + return; } default: break; } @@ -756,51 +659,21 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color) return; Q_D(QDirectFBPaintEngine); d->updateClip(); - if (d->unsupportedCompositionMode || !d->dfbCanHandleClip() || d->matrixRotShear) { + if (d->unsupportedCompositionMode + || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported) + || !d->dfbCanHandleClip()) { RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG()); d->lock(); QRasterPaintEngine::fillRect(rect, color); } else { d->unlock(); d->setDFBColor(color); - const QRect r = d->transform.mapRect(rect).toRect(); + const QRect r = state()->matrix.mapRect(rect).toRect(); d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()); } } -void QDirectFBPaintEngine::drawColorSpans(const QSpan *spans, int count, - uint color) -{ - Q_D(QDirectFBPaintEngine); - color = INV_PREMUL(color); - - QVarLengthArray<DFBRegion> lines(count); - int j = 0; - for (int i = 0; i < count; ++i) { - if (spans[i].coverage == 255) { - lines[j].x1 = spans[i].x; - lines[j].y1 = spans[i].y; - lines[j].x2 = spans[i].x + spans[i].len - 1; - lines[j].y2 = spans[i].y; - ++j; - } else { - DFBSpan span = { spans[i].x, spans[i].len }; - uint c = BYTE_MUL(color, spans[i].coverage); - // ### how does this play with setDFBColor - d->surface->SetColor(d->surface, - qRed(c), qGreen(c), qBlue(c), qAlpha(c)); - d->surface->FillSpans(d->surface, spans[i].y, &span, 1); - } - } - if (j > 0) { - d->surface->SetColor(d->surface, - qRed(color), qGreen(color), qBlue(color), - qAlpha(color)); - d->surface->DrawLines(d->surface, lines.data(), j); - } -} - void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, int x, int y, int length, uint const_alpha) @@ -834,9 +707,8 @@ void QDirectFBPaintEngine::initImageCache(int size) QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p) : surface(0), antialiased(false), simplePen(false), - matrixRotShear(false), scale(NoScale), lastLockedHeight(-1), - fbWidth(-1), fbHeight(-1), opacity(255), dirtyClip(true), - dfbHandledClip(false), dfbDevice(0), lockedMemory(0), + transformationType(0), opacity(255), dirtyClip(true), + dfbHandledClip(false), dfbDevice(0), unsupportedCompositionMode(false), q(p) { fb = QDirectFBScreen::instance()->dfb(); @@ -877,12 +749,9 @@ void QDirectFBPaintEnginePrivate::lock() // lock so we need to call the base implementation of prepare so // it updates its rasterBuffer to point to the new buffer address. Q_ASSERT(dfbDevice); - if (dfbDevice->lockFlags() != (DSLF_WRITE|DSLF_READ) - || dfbDevice->height() != lastLockedHeight - || dfbDevice->memory() != lockedMemory) { + if (dfbDevice->lockFlags() != (DSLF_WRITE|DSLF_READ)) { + dfbDevice->lockDirectFB(DSLF_READ|DSLF_WRITE); prepare(dfbDevice); - lastLockedHeight = dfbDevice->height(); - lockedMemory = dfbDevice->memory(); } } @@ -890,32 +759,26 @@ void QDirectFBPaintEnginePrivate::unlock() { Q_ASSERT(dfbDevice); dfbDevice->unlockDirectFB(); - lockedMemory = 0; } -void QDirectFBPaintEnginePrivate::setTransform(const QTransform &m) +void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform) { - transform = m; - matrixRotShear = (transform.m12() != 0 || transform.m21() != 0); + transformationType = transform.type(); if (qMin(transform.m11(), transform.m22()) < 0) { - scale = NegativeScale; - } else if (transform.m11() != 1 || transform.m22() != 1) { - scale = Scaled; - } else { - scale = NoScale; + transformationType |= QDirectFBPaintEnginePrivate::NegativeScale; } + setPen(q->state()->pen); } -void QDirectFBPaintEnginePrivate::setPen(const QPen &p) +void QDirectFBPaintEnginePrivate::setPen(const QPen &pen) { - pen = p; if (pen.style() == Qt::NoPen) { simplePen = true; } else if (pen.style() == Qt::SolidLine && !antialiased && pen.brush().style() == Qt::SolidPattern && pen.widthF() <= 1.0 - && (scale == NoScale || pen.isCosmetic())) { + && (transformationType < QTransform::TxScale || pen.isCosmetic())) { simplePen = true; } else { simplePen = false; @@ -927,12 +790,6 @@ void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode m unsupportedCompositionMode = (mode != QPainter::CompositionMode_SourceOver); } - -void QDirectFBPaintEnginePrivate::setOpacity(quint8 op) -{ - opacity = op; -} - void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints) { const bool old = antialiased; @@ -952,6 +809,13 @@ void QDirectFBPaintEnginePrivate::prepareForBlit(bool alpha) surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blittingFlags)); } +static inline uint ALPHA_MUL(uint x, uint a) +{ + uint t = x * a; + t = ((t + (t >> 8) + 0x80) >> 8) & 0xff; + return t; +} + void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) { Q_ASSERT(surface); @@ -962,67 +826,6 @@ void QDirectFBPaintEnginePrivate::setDFBColor(const QColor &color) surface->SetDrawingFlags(surface, alpha == 255 ? DSDRAW_NOFX : DSDRAW_BLEND); } -void QDirectFBPaintEnginePrivate::drawLines(const QLine *lines, int n) -{ - for (int i = 0; i < n; ++i) { - const QLine l = transform.map(lines[i]); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } -} - -void QDirectFBPaintEnginePrivate::drawLines(const QLineF *lines, int n) -{ - for (int i = 0; i < n; ++i) { - const QLine l = transform.map(lines[i]).toLine(); - surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); - } -} - -void QDirectFBPaintEnginePrivate::fillRegion(const QRegion ®ion) -{ - Q_ASSERT(isSimpleBrush(q->state()->brush)); - setDFBColor(q->state()->brush.color()); - const QVector<QRect> rects = region.rects(); - const int n = rects.size(); - fillRects(rects.constData(), n); -} - -void QDirectFBPaintEnginePrivate::fillRects(const QRect *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]); - surface->FillRectangle(surface, r.x(), r.y(), - r.width(), r.height()); - } -} - -void QDirectFBPaintEnginePrivate::fillRects(const QRectF *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]).toRect(); - surface->FillRectangle(surface, r.x(), r.y(), - r.width(), r.height()); - } -} - -void QDirectFBPaintEnginePrivate::drawRects(const QRect *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]); - surface->DrawRectangle(surface, r.x(), r.y(), - r.width() + 1, r.height() + 1); - } -} - -void QDirectFBPaintEnginePrivate::drawRects(const QRectF *rects, int n) -{ - for (int i = 0; i < n; ++i) { - const QRect r = transform.mapRect(rects[i]).toRect(); - surface->DrawRectangle(surface, r.x(), r.y(), - r.width() + 1, r.height() + 1); - } -} - IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) { #ifndef QT_DIRECTFB_IMAGECACHE @@ -1061,7 +864,7 @@ IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, boo void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src) { const QRect sr = src.toRect(); - const QRect dr = transform.mapRect(dest).toRect(); + const QRect dr = q->state()->matrix.mapRect(dest).toRect(); if (dr.isEmpty()) return; const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; @@ -1077,55 +880,107 @@ void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, DirectFBError("QDirectFBPaintEngine::drawPixmap()", result); } -void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, - const QPixmap &pixmap) +static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset) +{ + qreal pos = rect_pos - offset; + while (pos > rect_pos) + pos -= pixmapSize; + while (pos + pixmapSize < rect_pos) + pos += pixmapSize; + return pos; +} + +void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &off) { + Q_ASSERT(!dirtyClip); + Q_ASSERT(!(transformationType & BlitUnsupported)); + const QTransform &transform = q->state()->matrix; + const QRect destinationRect = transform.mapRect(dest).toRect().normalized(); + QRect newClip = destinationRect; + if (!currentClip.isEmpty()) + newClip &= currentClip; + + if (newClip.isNull()) + return; + + const DFBRegion clip = { + newClip.x(), + newClip.y(), + newClip.x() + newClip.width() - 1, + newClip.y() + newClip.height() - 1 + }; + surface->SetClip(surface, &clip); + + QPointF offset = off; + Q_ASSERT(transform.type() <= QTransform::TxScale); prepareForBlit(pixmap.hasAlphaChannel()); QPixmapData *data = pixmap.pixmapData(); Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); - IDirectFBSurface *s = dfbData->directFBSurface(); - const QRect dr = transform.mapRect(dest).toRect(); - DFBResult result = DFB_OK; - - if (scale == NoScale && dr == QRect(0, 0, fbWidth, fbHeight)) { - result = surface->TileBlit(surface, s, 0, 0, 0); - } else if (scale == NoScale) { - const int dx = pixmap.width(); - const int dy = pixmap.height(); - const DFBRectangle rect = { 0, 0, dx, dy }; - QVarLengthArray<DFBRectangle> rects; - QVarLengthArray<DFBPoint> points; - - for (int y = dr.y(); y <= dr.bottom(); y += dy) { - for (int x = dr.x(); x <= dr.right(); x += dx) { - rects.append(rect); - const DFBPoint point = { x, y }; - points.append(point); + dfbData->unlockDirectFB(); + const QSize pixmapSize = dfbData->size(); + IDirectFBSurface *sourceSurface = dfbData->directFBSurface(); + if (transform.isScaling()) { + Q_ASSERT(qMin(transform.m11(), transform.m22()) >= 0); + offset.rx() *= transform.m11(); + offset.ry() *= transform.m22(); + + const QSizeF mappedSize(pixmapSize.width() * transform.m11(), pixmapSize.height() * transform.m22()); + qreal y = ::fixCoord(destinationRect.y(), mappedSize.height(), offset.y()); + const qreal startX = ::fixCoord(destinationRect.x(), mappedSize.width(), offset.x()); + while (y <= destinationRect.bottom()) { + qreal x = startX; + while (x <= destinationRect.right()) { + const DFBRectangle destination = { qRound(x), qRound(y), mappedSize.width(), mappedSize.height() }; + surface->StretchBlit(surface, sourceSurface, 0, &destination); + x += mappedSize.width(); } + y += mappedSize.height(); } - result = surface->BatchBlit(surface, s, rects.constData(), - points.constData(), points.size()); } else { - const QRect sr = transform.mapRect(QRect(0, 0, pixmap.width(), pixmap.height())); - const int dx = sr.width(); - const int dy = sr.height(); - const DFBRectangle sRect = { 0, 0, dx, dy }; - - for (int y = dr.y(); y <= dr.bottom(); y += dy) { - for (int x = dr.x(); x <= dr.right(); x += dx) { - const DFBRectangle dRect = { x, y, dx, dy }; - result = surface->StretchBlit(surface, s, &sRect, &dRect); - if (result != DFB_OK) { - y = dr.bottom() + 1; - break; - } + qreal y = ::fixCoord(destinationRect.y(), pixmapSize.height(), offset.y()); + const qreal startX = ::fixCoord(destinationRect.x(), pixmapSize.width(), offset.x()); + int horizontal = qMax(1, destinationRect.width() / pixmapSize.width()) + 1; + if (startX != destinationRect.x()) + ++horizontal; + int vertical = qMax(1, destinationRect.height() / pixmapSize.height()) + 1; + if (y != destinationRect.y()) + ++vertical; + + const int maxCount = (vertical * horizontal); + QVarLengthArray<DFBRectangle, 16> sourceRects(maxCount); + QVarLengthArray<DFBPoint, 16> points(maxCount); + + int i = 0; + while (y <= destinationRect.bottom()) { + Q_ASSERT(i < maxCount); + qreal x = startX; + while (x <= destinationRect.right()) { + points[i].x = qRound(x); + points[i].y = qRound(y); + sourceRects[i].x = 0; + sourceRects[i].y = 0; + sourceRects[i].w = int(pixmapSize.width()); + sourceRects[i].h = int(pixmapSize.height()); + x += pixmapSize.width(); + ++i; } + y += pixmapSize.height(); } + surface->BatchBlit(surface, sourceSurface, sourceRects.constData(), points.constData(), i); } - if (result != DFB_OK) - DirectFBError("QDirectFBPaintEngine::drawTiledPixmap()", result); + if (currentClip.isEmpty()) { + surface->SetClip(surface, 0); + } else { + const DFBRegion clip = { + currentClip.x(), + currentClip.y(), + currentClip.x() + currentClip.width(), + currentClip.y() + currentClip.height() + }; + surface->SetClip(surface, &clip); + } } void QDirectFBPaintEnginePrivate::updateClip() @@ -1133,6 +988,7 @@ void QDirectFBPaintEnginePrivate::updateClip() if (!dirtyClip) return; + currentClip = QRect(); const QClipData *clipData = clip(); if (!clipData || !clipData->enabled) { surface->SetClip(surface, NULL); @@ -1145,6 +1001,8 @@ void QDirectFBPaintEnginePrivate::updateClip() clipData->clipRect.y() + clipData->clipRect.height() }; surface->SetClip(surface, &r); + currentClip = clipData->clipRect.normalized(); + // ### is this guaranteed to always be normalized? dfbHandledClip = true; } else if (clipData->hasRegionClip && ignoreSystemClip && clipData->clipRegion == systemClip) { dfbHandledClip = true; @@ -1161,4 +1019,126 @@ void QDirectFBPaintEnginePrivate::systemStateChanged() QRasterPaintEnginePrivate::systemStateChanged(); } +IDirectFBSurface *SurfaceCache::getSurface(const uint *buf, int size) +{ + if (buffer == buf && bufsize == size) + return surface; + + clear(); + + const DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(buf, size); + surface = QDirectFBScreen::instance()->createDFBSurface(description, QDirectFBScreen::TrackSurface); + if (!surface) + qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); + + buffer = const_cast<uint*>(buf); + bufsize = size; + + return surface; +} + +void SurfaceCache::clear() +{ + if (surface && QDirectFBScreen::instance()) + QDirectFBScreen::instance()->releaseDFBSurface(surface); + surface = 0; + buffer = 0; + bufsize = 0; +} + + +static inline QRect mapRect(const QTransform &transform, const QRect &rect) { return transform.mapRect(rect); } +static inline QRect mapRect(const QTransform &transform, const QRectF &rect) { return transform.mapRect(rect).toRect(); } +static inline QLine map(const QTransform &transform, const QLine &line) { return transform.map(line); } +static inline QLine map(const QTransform &transform, const QLineF &line) { return transform.map(line).toLine(); } +template <class T> +static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + if (n == 1) { + const QLine l = ::map(transform, lines[0]); + surface->DrawLine(surface, l.x1(), l.y1(), l.x2(), l.y2()); + } else { + QVarLengthArray<DFBRegion, 32> lineArray(n); + for (int i=0; i<n; ++i) { + const QLine l = ::map(transform, lines[i]); + lineArray[i].x1 = l.x1(); + lineArray[i].y1 = l.y1(); + lineArray[i].x2 = l.x2(); + lineArray[i].y2 = l.y2(); + } + surface->DrawLines(surface, lineArray.constData(), n); + } +} + +template <class T> +static inline void fillRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + if (n == 1) { + const QRect r = ::mapRect(transform, rects[0]); + surface->FillRectangle(surface, r.x(), r.y(), r.width(), r.height()); + } else { + QVarLengthArray<DFBRectangle, 32> rectArray(n); + for (int i=0; i<n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + rectArray[i].x = r.x(); + rectArray[i].y = r.y(); + rectArray[i].w = r.width(); + rectArray[i].h = r.height(); + } + surface->FillRectangles(surface, rectArray.constData(), n); + } +} + +template <class T> +static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface) +{ + for (int i=0; i<n; ++i) { + const QRect r = ::mapRect(transform, rects[i]); + surface->DrawRectangle(surface, r.x(), r.y(), r.width(), r.height()); + } +} + +#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS +template <typename T> inline const T *ptr(const T &t) { return &t; } +template <> inline const bool* ptr<bool>(const bool &) { return 0; } +template <typename device, typename T1, typename T2, typename T3> +static void rasterFallbackWarn(const char *msg, const char *func, const device *dev, + uint transformationType, bool simplePen, + bool dfbHandledClip, bool unsupportedCompositionMode, + const char *nameOne, const T1 &one, + const char *nameTwo, const T2 &two, + const char *nameThree, const T3 &three) +{ + QString out; + QDebug dbg(&out); + dbg << msg << (QByteArray(func) + "()") << "painting on"; + if (dev->devType() == QInternal::Widget) { + dbg << static_cast<const QWidget*>(dev); + } else { + dbg << dev << "of type" << dev->devType(); + } + + dbg << QString("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0')) + << "simplePen" << simplePen + << "dfbHandledClip" << dfbHandledClip + << "unsupportedCompositionMode" << unsupportedCompositionMode; + + const T1 *t1 = ptr(one); + const T2 *t2 = ptr(two); + const T3 *t3 = ptr(three); + + if (t1) { + dbg << nameOne << *t1; + if (t2) { + dbg << nameTwo << *t2; + if (t3) { + dbg << nameThree << *t3; + } + } + } + qWarning("%s", qPrintable(out)); +} +#endif + + #endif // QT_NO_DIRECTFB |