diff options
author | Anders Bakken <anders.bakken@nokia.com> | 2009-04-08 23:49:08 (GMT) |
---|---|---|
committer | Anders Bakken <anders.bakken@nokia.com> | 2009-04-09 01:23:26 (GMT) |
commit | 6b494c48efa21f4ed3e2367f8bed8e138fd58190 (patch) | |
tree | a42d6c2447854b79168463088648cf18bebc4791 /src/plugins/gfxdrivers | |
parent | d8dda2706408e0c9558966e74376834d290dc6e3 (diff) | |
download | Qt-6b494c48efa21f4ed3e2367f8bed8e138fd58190.zip Qt-6b494c48efa21f4ed3e2367f8bed8e138fd58190.tar.gz Qt-6b494c48efa21f4ed3e2367f8bed8e138fd58190.tar.bz2 |
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 <qt-info@nokia.com>
Diffstat (limited to 'src/plugins/gfxdrivers')
-rw-r--r-- | src/plugins/gfxdrivers/directfb/directfb.pro | 1 | ||||
-rw-r--r-- | src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp | 161 | ||||
-rw-r--r-- | 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; y<height; ++y) { + for (int x=0; x<width; ++x) { + if ((((uint *)bits)[x] & 0xff000000) != 0xff000000) { + return true; + } + } + bits += bytes_per_line; + } + break; + + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + for (int y=0; y<height; ++y) { + while (bits < end_bits) { + if (bits[0] != 0) { + return true; + } + bits += 3; + } + bits = end_bits; + end_bits += bytes_per_line; + } + break; + + case QImage::Format_ARGB6666_Premultiplied: + for (int y=0; y<height; ++y) { + while (bits < end_bits) { + if ((bits[0] & 0xfc) != 0) { + return true; + } + bits += 3; + } + bits = end_bits; + end_bits += bytes_per_line; + } + break; + + case QImage::Format_ARGB4444_Premultiplied: + for (int y=0; y<height; ++y) { + while (bits < end_bits) { + if ((bits[0] & 0xf0) != 0) { + return true; + } + bits += 2; + } + bits = end_bits; + end_bits += bytes_per_line; + } + break; + + default: + break; + } + + return false; +} + void QDirectFBPixmapData::fromImage(const QImage &img, - Qt::ImageConversionFlags) + Qt::ImageConversionFlags flags) { - const QImage::Format format = img.hasAlphaChannel() ? - screen->alphaPixmapFormat() - : 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<const QDirectFBPixmapData*>(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 |