diff options
author | Anders Bakken <anders.bakken@nokia.com> | 2009-05-05 21:37:53 (GMT) |
---|---|---|
committer | Anders Bakken <anders.bakken@nokia.com> | 2009-05-05 22:13:28 (GMT) |
commit | 8ee920d09ad139aedb14eaacc3f9c198d43e4351 (patch) | |
tree | 6b04d442cb98fbb42247a112b3ae357365fb03c2 /src/plugins/gfxdrivers | |
parent | f06d186c3b9b053132d8107f843317067238083f (diff) | |
download | Qt-8ee920d09ad139aedb14eaacc3f9c198d43e4351.zip Qt-8ee920d09ad139aedb14eaacc3f9c198d43e4351.tar.gz Qt-8ee920d09ad139aedb14eaacc3f9c198d43e4351.tar.bz2 |
Refactored image caching
Make image caching a lot cleaner and more sensible.
By default we do not cache images since creating a preallocated surface
is quick and we don't really want to waste memory. In the case where the
driver does not support preallocated surfaces you can enable image
caching to speed up drawImage.
Reviewed-by: TrustMe
Diffstat (limited to 'src/plugins/gfxdrivers')
7 files changed, 147 insertions, 141 deletions
diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro index b128514..5c60b2f 100644 --- a/src/plugins/gfxdrivers/directfb/directfb.pro +++ b/src/plugins/gfxdrivers/directfb/directfb.pro @@ -6,6 +6,7 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers # These defines might be necessary if your DirectFB driver doesn't # support all of the DirectFB API. # +#DEFINES += QT_DIRECTFB_IMAGECACHE #DEFINES += QT_NO_DIRECTFB_WM #DEFINES += QT_NO_DIRECTFB_LAYER #DEFINES += QT_NO_DIRECTFB_PALETTE @@ -41,4 +42,3 @@ SOURCES = qdirectfbscreen.cpp \ QMAKE_CXXFLAGS += $$QT_CFLAGS_DIRECTFB LIBS += $$QT_LIBS_DIRECTFB DEFINES += $$QT_DEFINES_DIRECTFB - diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index 57b2418..317f930 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -193,61 +193,21 @@ private: }; -class CachedImage +#ifdef QT_DIRECTFB_IMAGECACHE +#include <private/qimage_p.h> +struct CachedImage { -public: - CachedImage(const QImage &image); - ~CachedImage(); - - IDirectFBSurface *surface() { return s; } - -private: - IDirectFBSurface *s; -}; - -CachedImage::CachedImage(const QImage &image) - : s(0) -{ - IDirectFBSurface *tmpSurface = 0; - DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(image); - QDirectFBScreen* screen = QDirectFBScreen::instance(); - - tmpSurface = screen->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!tmpSurface) { - qWarning("CachedImage CreateSurface failed!"); - return; + IDirectFBSurface *surface; + ~CachedImage() + { + if (surface && QDirectFBScreen::instance()) { + QDirectFBScreen::instance()->releaseDFBSurface(surface); + } } - -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(tmpSurface, image); -#endif - - description.flags = DFBSurfaceDescriptionFlags(description.flags & ~DSDESC_PREALLOCATED); - - s = screen->createDFBSurface(description, QDirectFBScreen::TrackSurface); - if (!s) - qWarning("QDirectFBPaintEngine failed caching image"); - -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(s, image); +}; +static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB #endif - if (s) { - s->SetBlittingFlags(s, DSBLIT_NOFX); - s->Blit(s, tmpSurface, 0, 0, 0); - s->ReleaseSource(s); - } - if (tmpSurface) - screen->releaseDFBSurface(tmpSurface); -} - -CachedImage::~CachedImage() -{ - if (s && QDirectFBScreen::instance()) - QDirectFBScreen::instance()->releaseDFBSurface(s); -} - -static QCache<qint64, CachedImage> imageCache(4*1024*1024); // 4 MB class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate { public: @@ -291,11 +251,8 @@ public: void fillRects(const QRectF *rects, int count); void drawRects(const QRectF *rects, int count); - - void drawPixmap(const QRectF &dest, - const QPixmap &pixmap, const QRectF &src); void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap); - void drawImage(const QRectF &dest, const QImage &image, const QRectF &src); + void blit(const QRectF &dest, IDirectFBSurface *surface, const QRectF &src); inline void updateClip(); inline void setClipDirty(); @@ -304,6 +261,12 @@ public: void begin(QPaintDevice *device); void end(); + static IDirectFBSurface *getSurface(const QImage &img, bool *release); + +#ifdef QT_DIRECTFB_IMAGECACHE + static inline int cacheCost(const QImage &img) { return img.width() * img.height() * img.depth() / 8; } +#endif + void prepareForBlit(bool alpha); SurfaceCache *surfaceCache; QTransform transform; @@ -338,9 +301,6 @@ QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p fb = QDirectFBScreen::instance()->dfb(); ignoreSystemClip = QDirectFBScreen::instance()->directFBFlags() & QDirectFBScreen::IgnoreSystemClip; surfaceCache = new SurfaceCache; - static int cacheLimit = qgetenv("QT_DIRECTFB_IMAGECACHE").toInt(); - if (cacheLimit > 0) - imageCache.setMaxCost(cacheLimit * 1024); } QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate() @@ -634,15 +594,43 @@ void QDirectFBPaintEnginePrivate::drawRects(const QRectF *rects, int n) } } -void QDirectFBPaintEnginePrivate::drawPixmap(const QRectF &dest, - const QPixmap &pixmap, - const QRectF &src) +IDirectFBSurface *QDirectFBPaintEnginePrivate::getSurface(const QImage &img, bool *release) +{ +#ifndef QT_DIRECTFB_IMAGECACHE + *release = true; + return QDirectFBScreen::instance()->createDFBSurface(img, QDirectFBScreen::DontTrackSurface); +#else + const qint64 key = img.cacheKey(); + *release = false; + if (imageCache.contains(key)) { + return imageCache[key]->surface; + } + + const int cost = cacheCost(img); + const bool cache = cost <= imageCache.maxCost(); + QDirectFBScreen *screen = QDirectFBScreen::instance(); + const QImage::Format format = (img.format() == screen->alphaPixmapFormat() || QDirectFBPixmapData::hasAlphaChannel(img) + ? screen->alphaPixmapFormat() : screen->pixelFormat()); + + IDirectFBSurface *surface = screen->copyToDFBSurface(img, format, + cache + ? QDirectFBScreen::TrackSurface + : QDirectFBScreen::DontTrackSurface); + if (cache) { + CachedImage *cachedImage = new CachedImage; + const_cast<QImage&>(img).data_ptr()->is_cached = true; + cachedImage->surface = surface; + imageCache.insert(key, cachedImage, cost); + } else { + *release = true; + } + return surface; +#endif +} + + +void QDirectFBPaintEnginePrivate::blit(const QRectF &dest, IDirectFBSurface *s, const QRectF &src) { - 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 sr = src.toRect(); const QRect dr = transform.mapRect(dest).toRect(); const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; @@ -709,64 +697,6 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, DirectFBError("QDirectFBPaintEngine::drawTiledPixmap()", result); } -void QDirectFBPaintEnginePrivate::drawImage(const QRectF &dest, - const QImage &image, - const QRectF &src) -{ - Q_ASSERT(QDirectFBScreen::getSurfacePixelFormat(image.format()) != DSPF_UNKNOWN); - CachedImage *img = imageCache[image.cacheKey()]; - IDirectFBSurface *imgSurface = 0; - bool doRelease = false; - - if (img) { - imgSurface = img->surface(); - } else { - const int cost = image.width() * image.height() * image.depth() / 8; - if (cost <= imageCache.maxCost()) { - img = new CachedImage(image); - imgSurface = img->surface(); - if (imgSurface) { - imageCache.insert(image.cacheKey(), img, cost); - } else { - delete img; - img = 0; - } - } - - if (!imgSurface) { - DFBSurfaceDescription description = QDirectFBScreen::getSurfaceDescription(image); - imgSurface = QDirectFBScreen::instance()->createDFBSurface(description, - QDirectFBScreen::DontTrackSurface); - if (!imgSurface) { - qWarning("QDirectFBPaintEnginePrivate::drawImage"); - return; - } - -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(surface, image); -#endif - doRelease = (imgSurface != 0); - } - } - - const QRect sr = src.toRect(); - const QRect dr = transform.mapRect(dest).toRect(); - const DFBRectangle sRect = { sr.x(), sr.y(), sr.width(), sr.height() }; - - prepareForBlit(image.hasAlphaChannel()); - if (dr.size() == sr.size()) { - surface->Blit(surface, imgSurface, &sRect, dr.x(), dr.y()); - } else { - const DFBRectangle dRect = { dr.x(), dr.y(), - dr.width(), dr.height() }; - surface->StretchBlit(surface, imgSurface, &sRect, &dRect); - } - if (doRelease) { - surface->ReleaseSource(surface); - imgSurface->Release(imgSurface); - } -} - void QDirectFBPaintEnginePrivate::updateClip() { if (!dirtyClip) @@ -828,8 +758,6 @@ bool QDirectFBPaintEngine::end() return QRasterPaintEngine::end(); } - - void QDirectFBPaintEngine::clipEnabledChanged() { Q_D(QDirectFBPaintEngine); @@ -1004,13 +932,36 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, Qt::ImageConversionFlags flags) { Q_D(QDirectFBPaintEngine); - Q_UNUSED(flags); // XXX + Q_UNUSED(flags); + + /* This is hard to read. The way it works is like this: + + - If you do not have support for preallocated surfaces and do not use an + image cache we always fall back to raster engine. + + - If it's rotated/sheared/mirrored (negative scale) or we can't + clip it we fall back to raster engine. + + - If we don't cache the image, but we do have support for + preallocated surfaces we fall back to the raster engine if the + image is in a format DirectFB can't handle. + + - If we do cache the image but don't have support for preallocated + images and the cost of caching the image (bytes used) is higher + than the max image cache size we fall back to raster engine. + */ -#ifndef QT_NO_DIRECTFB_PREALLOCATED d->updateClip(); - if (!d->dfbCanHandleClip(r) || d->matrixRotShear +#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE + if (d->matrixRotShear || d->scale == QDirectFBPaintEnginePrivate::NegativeScale - || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN) + || !d->dfbCanHandleClip(r) +#ifndef QT_DIRECTFB_IMAGECACHE + || QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN +#elif defined QT_NO_DIRECTFB_PREALLOCATED + || QDirectFBPaintEnginePrivate::cacheCost(image) > imageCache.maxCost() +#endif + ) #endif { RASTERFALLBACK(DRAW_IMAGE, r, image.size(), sr); @@ -1018,10 +969,16 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image, QRasterPaintEngine::drawImage(r, image, sr, flags); return; } - -#ifndef QT_NO_DIRECTFB_PREALLOCATED +#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE d->unlock(); - d->drawImage(r, image, sr); + bool release; + IDirectFBSurface *imgSurface = d->getSurface(image, &release); + d->prepareForBlit(QDirectFBScreen::hasAlpha(imgSurface)); + d->blit(r, imgSurface, sr); + if (release) { + imgSurface->ReleaseSource(imgSurface); + imgSurface->Release(imgSurface); + } #endif } @@ -1048,7 +1005,12 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap, QRasterPaintEngine::drawImage(r, *img, sr); } else { d->unlock(); - d->drawPixmap(r, pixmap, sr); + d->prepareForBlit(pixmap.hasAlphaChannel()); + QPixmapData *data = pixmap.pixmapData(); + Q_ASSERT(data->classId() == QPixmapData::DirectFBClass); + QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data); + IDirectFBSurface *s = dfbData->directFBSurface(); + d->blit(r, s, sr); } } @@ -1258,4 +1220,19 @@ void QDirectFBPaintEngine::drawBufferSpan(const uint *buffer, int bufsize, d->surface->Blit(d->surface, src, &rect, x, y); } +#ifdef QT_DIRECTFB_IMAGECACHE +static void cachedImageCleanupHook(qint64 key) +{ + delete imageCache.take(key); +} +void QDirectFBPaintEngine::initImageCache(int size) +{ + Q_ASSERT(size >= 0); + imageCache.setMaxCost(size); + typedef void (*_qt_image_cleanup_hook_64)(qint64); + extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64; + qt_image_cleanup_hook_64 = ::cachedImageCleanupHook; +} + +#endif // QT_DIRECTFB_IMAGECACHE #endif // QT_NO_DIRECTFB diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h index e79ec61..d33255b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.h @@ -106,6 +106,7 @@ public: virtual void clip(const QVectorPath &path, Qt::ClipOperation op); virtual void clip(const QRect &rect, Qt::ClipOperation op); + static void initImageCache(int size); }; QT_END_HEADER diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index f7c428b..7297a99 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -157,6 +157,16 @@ static bool checkForAlphaPixels(const QImage &img) return false; } +bool QDirectFBPixmapData::hasAlphaChannel(const QImage &img) +{ +#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION + return ::checkForAlphaPixels(img); +#else + return img.hasAlphaChannel(); +#endif +} + + void QDirectFBPixmapData::fromImage(const QImage &i, Qt::ImageConversionFlags flags) { @@ -166,7 +176,7 @@ void QDirectFBPixmapData::fromImage(const QImage &i, const QImage img = (i.depth() == 1 ? i.convertToFormat(screen->alphaPixmapFormat()) : i); if (img.hasAlphaChannel() #ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION - && (flags & Qt::NoOpaqueDetection || ::checkForAlphaPixels(img)) + && (flags & Qt::NoOpaqueDetection || QDirectFBPixmapData::hasAlphaChannel(img)) #endif ) { alpha = true; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h index 697e5ce..7cd60d6 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -75,6 +75,7 @@ public: // Pure virtual in QPixmapData, so re-implement here and delegate to QDirectFBPaintDevice int metric(QPaintDevice::PaintDeviceMetric m) const {return QDirectFBPaintDevice::metric(m);} inline QImage::Format pixelFormat() const { return format; } + static bool hasAlphaChannel(const QImage &img); private: void invalidate(); QDirectFBPaintEngine *engine; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index ab60214..25e24fd 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -113,9 +113,9 @@ QDirectFBScreenPrivate::~QDirectFBScreenPrivate() delete keyboard; #endif - foreach (IDirectFBSurface *surf, allocatedSurfaces) - surf->Release(surf); - allocatedSurfaces.clear(); + for (QSet<IDirectFBSurface*>::const_iterator it = allocatedSurfaces.begin(); it != allocatedSurfaces.end(); ++it) { + (*it)->Release(*it); + } if (dfbSurface) dfbSurface->Release(dfbSurface); @@ -350,6 +350,7 @@ QDirectFBScreen::DirectFBFlags QDirectFBScreen::directFBFlags() const { return d_ptr->directFBFlags; } + IDirectFB *QDirectFBScreen::dfb() { return d_ptr->dfb; @@ -900,6 +901,12 @@ bool QDirectFBScreen::connect(const QString &displaySpec) d_ptr->directFBFlags |= BoundingRectFlip; } +#ifdef QT_DIRECTFB_IMAGECACHE + int imageCacheSize = 4 * 1024 * 1024; // 4 MB + ::setIntOption(displayArgs, QLatin1String("imagecachesize"), &imageCacheSize); + QDirectFBPaintEngine::initImageCache(imageCacheSize); +#endif + if (displayArgs.contains(QLatin1String("ignoresystemclip"), Qt::CaseInsensitive)) d_ptr->directFBFlags |= IgnoreSystemClip; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index e91a06b..84199a2 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -105,8 +105,6 @@ public: TrackSurface = 1 }; Q_DECLARE_FLAGS(SurfaceCreationOptions, SurfaceCreationOption); - IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc, - SurfaceCreationOptions options); IDirectFBSurface *createDFBSurface(const QImage &image, SurfaceCreationOptions options); IDirectFBSurface *createDFBSurface(const QSize &size, @@ -130,6 +128,7 @@ public: static bool initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, QImage::Format format); static inline bool isPremultiplied(QImage::Format format); static inline bool hasAlpha(DFBSurfacePixelFormat format); + static inline bool hasAlpha(IDirectFBSurface *surface); QImage::Format alphaPixmapFormat() const; #ifndef QT_NO_DIRECTFB_PALETTE @@ -140,11 +139,14 @@ public: static uchar *lockSurface(IDirectFBSurface *surface, uint flags, int *bpl = 0); private: + IDirectFBSurface *createDFBSurface(DFBSurfaceDescription desc, + SurfaceCreationOptions options); void compose(const QRegion &r); void blit(IDirectFBSurface *src, const QPoint &topLeft, const QRegion ®ion); QDirectFBScreenPrivate *d_ptr; + friend class SurfaceCache; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::SurfaceCreationOptions); @@ -186,6 +188,14 @@ inline bool QDirectFBScreen::hasAlpha(DFBSurfacePixelFormat format) } } +inline bool QDirectFBScreen::hasAlpha(IDirectFBSurface *surface) +{ + Q_ASSERT(surface); + DFBSurfacePixelFormat format; + surface->GetPixelFormat(surface, &format); + return QDirectFBScreen::hasAlpha(format); +} + QT_END_HEADER #endif // QDIRECTFBSCREEN_H |