From 6b494c48efa21f4ed3e2367f8bed8e138fd58190 Mon Sep 17 00:00:00 2001 From: Anders Bakken Date: Wed, 8 Apr 2009 16:49:08 -0700 Subject: Be smarter about alpha formats Try harder to prevent blends by explicitly checking for alpha pixels in the source image (unless asked not to). Can be defined out by #defining QT_NO_DIRECTFB_OPAQUE_DETECTION Reviewed-by: Donald --- src/plugins/gfxdrivers/directfb/directfb.pro | 1 + .../gfxdrivers/directfb/qdirectfbpixmap.cpp | 161 +++++++++++++++++---- src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h | 3 + 3 files changed, 133 insertions(+), 32 deletions(-) diff --git a/src/plugins/gfxdrivers/directfb/directfb.pro b/src/plugins/gfxdrivers/directfb/directfb.pro index 399044e..89a289c 100644 --- a/src/plugins/gfxdrivers/directfb/directfb.pro +++ b/src/plugins/gfxdrivers/directfb/directfb.pro @@ -13,6 +13,7 @@ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/gfxdrivers #DEFINES += QT_NO_DIRECTFB_MOUSE #DEFINES += QT_NO_DIRECTFB_KEYBOARD #DEFINES += QT_DIRECTFB_TIMING +#DEFINES += QT_NO_DIRECTFB_OPAQUE_DETECTION target.path = $$[QT_INSTALL_PLUGINS]/gfxdrivers INSTALLS += target diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index a20b66a..a4e235b 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -51,7 +51,7 @@ static int global_ser_no = 0; QDirectFBPixmapData::QDirectFBPixmapData(PixelType pixelType) : QPixmapData(pixelType, DirectFBClass), - engine(0) + engine(0), format(QImage::Format_Invalid), alpha(false) { setSerialNumber(0); } @@ -67,16 +67,18 @@ QDirectFBPixmapData::~QDirectFBPixmapData() void QDirectFBPixmapData::resize(int width, int height) { if (width <= 0 || height <= 0) { - setSerialNumber(0); + invalidate(); return; } - dfbSurface = screen->createDFBSurface(QSize(width, height), - screen->pixelFormat(), - QDirectFBScreen::TrackSurface); - forceRaster = (screen->pixelFormat() == QImage::Format_RGB32); + format = screen->pixelFormat(); + dfbSurface = QDirectFBScreen::instance()->createDFBSurface(QSize(width, height), + format, + QDirectFBScreen::TrackSurface); + alpha = false; + forceRaster = (format == QImage::Format_RGB32); if (!dfbSurface) { - setSerialNumber(0); + invalidate(); qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface"); return; } @@ -84,18 +86,98 @@ void QDirectFBPixmapData::resize(int width, int height) setSerialNumber(++global_ser_no); } + +// mostly duplicated from qimage.cpp (QImageData::checkForAlphaPixels) +static bool checkForAlphaPixels(const QImage &img) +{ + const uchar *bits = img.bits(); + const int bytes_per_line = img.bytesPerLine(); + const uchar *end_bits = bits + bytes_per_line; + const int width = img.width(); + const int height = img.height(); + switch (img.format()) { + case QImage::Format_Indexed8: + return img.hasAlphaChannel(); + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + for (int y=0; yalphaPixmapFormat() - : screen->pixelFormat(); + Q_ASSERT(img.depth() != 1); // these should be handled by QRasterPixmapData + if (img.hasAlphaChannel() +#ifndef QT_NO_DIRECTFB_OPAQUE_DETECTION + && (flags & Qt::NoOpaqueDetection || ::checkForAlphaPixels(img)) +#endif + ) { + alpha = true; + format = screen->alphaPixmapFormat(); + } else { + alpha = false; + format = screen->pixelFormat(); + } dfbSurface = screen->copyToDFBSurface(img, format, QDirectFBScreen::TrackSurface); forceRaster = (format == QImage::Format_RGB32); if (!dfbSurface) { qWarning("QDirectFBPixmapData::fromImage()"); - setSerialNumber(0); + invalidate(); return; } setSerialNumber(++global_ser_no); @@ -110,15 +192,15 @@ void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect) IDirectFBSurface *src = static_cast(data)->directFBSurface(); const bool hasAlpha = data->hasAlphaChannel(); - const QImage::Format format = (hasAlpha - ? screen->alphaPixmapFormat() - : screen->pixelFormat()); + format = (hasAlpha + ? QDirectFBScreen::instance()->alphaPixmapFormat() + : QDirectFBScreen::instance()->pixelFormat()); dfbSurface = screen->createDFBSurface(rect.size(), format, QDirectFBScreen::TrackSurface); if (!dfbSurface) { qWarning("QDirectFBPixmapData::copy()"); - setSerialNumber(0); + invalidate(); return; } forceRaster = (format == QImage::Format_RGB32); @@ -135,13 +217,28 @@ void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect) dfbSurface->ReleaseSource(dfbSurface); if (result != DFB_OK) { DirectFBError("QDirectFBPixmapData::copy()", result); - setSerialNumber(0); + invalidate(); return; } setSerialNumber(++global_ser_no); } +static inline bool isOpaqueFormat(QImage::Format format) +{ + switch (format) { + case QImage::Format_RGB32: + case QImage::Format_RGB16: + case QImage::Format_RGB666: + case QImage::Format_RGB555: + case QImage::Format_RGB888: + case QImage::Format_RGB444: + return true; + default: + break; + } + return false; +} void QDirectFBPixmapData::fill(const QColor &color) { @@ -150,17 +247,19 @@ void QDirectFBPixmapData::fill(const QColor &color) Q_ASSERT(dfbSurface); - if (color.alpha() < 255 && !hasAlphaChannel()) { + alpha = (color.alpha() < 255); + if (alpha && ::isOpaqueFormat(format)) { QSize size; dfbSurface->GetSize(dfbSurface, &size.rwidth(), &size.rheight()); screen->releaseDFBSurface(dfbSurface); + format = screen->alphaPixmapFormat(); dfbSurface = screen->createDFBSurface(size, screen->alphaPixmapFormat(), QDirectFBScreen::TrackSurface); forceRaster = false; setSerialNumber(++global_ser_no); if (!dfbSurface) { - qWarning("QDirectFBPixmapData::fill()"); - setSerialNumber(0); + qWarning("QDirecttFBPixmapData::fill()"); + invalidate(); return; } } @@ -186,15 +285,7 @@ void QDirectFBPixmapData::fill(const QColor &color) bool QDirectFBPixmapData::hasAlphaChannel() const { - if (!serialNumber()) - return false; - DFBSurfacePixelFormat format; - dfbSurface->GetPixelFormat(dfbSurface, &format); - return QDirectFBScreen::hasAlpha(format); - - // We don't need to ask DFB for this really. Can just keep track - // of what image format this has. It should always have either - // QDirectFBScreen::alphaPixmapFormat() or QScreen::pixelFormat() + return alpha; } QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, @@ -221,11 +312,10 @@ QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, return QPixmap(); QDirectFBPixmapData *data = new QDirectFBPixmapData(QPixmapData::PixmapType); - QImage::Format format = screen->pixelFormat(); DFBSurfaceBlittingFlags flags = DSBLIT_NOFX; - if (hasAlphaChannel()) { + data->alpha = alpha; + if (alpha) { flags = DSBLIT_BLEND_ALPHACHANNEL; - format = screen->alphaPixmapFormat(); } data->dfbSurface = screen->createDFBSurface(size, format, @@ -285,3 +375,10 @@ QImage* QDirectFBPixmapData::buffer() lockDirectFB(); return lockedImage; } + +void QDirectFBPixmapData::invalidate() +{ + setSerialNumber(0); + alpha = false; + format = QImage::Format_Invalid; +} diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h index 32676f8..7aa6df8 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h @@ -75,7 +75,10 @@ public: int metric(QPaintDevice::PaintDeviceMetric m) const {return QDirectFBPaintDevice::metric(m);} private: + void invalidate(); QDirectFBPaintEngine *engine; + QImage::Format format; + bool alpha; }; QT_END_HEADER -- cgit v0.12