diff options
author | Anders Bakken <anders.bakken@nokia.com> | 2009-03-26 06:09:15 (GMT) |
---|---|---|
committer | Tom Cooksey <thomas.cooksey@nokia.com> | 2009-03-27 15:43:51 (GMT) |
commit | 43c5656d834739e86f2895cfbf3d539bb8c7c498 (patch) | |
tree | b52da52c77fd0b87913012bc6b5a0c3378dabe63 /src/plugins | |
parent | 062c476d378022a49307aca136cb9aab381e0814 (diff) | |
download | Qt-43c5656d834739e86f2895cfbf3d539bb8c7c498.zip Qt-43c5656d834739e86f2895cfbf3d539bb8c7c498.tar.gz Qt-43c5656d834739e86f2895cfbf3d539bb8c7c498.tar.bz2 |
Major surface related fix
Make sure all QDirectFBPaintDevice surfaces always are created with a
format that is either QScreen::pixelFormat() or
QDirectFBScreen::alphaPixmapFormat().
Also, clean up surface creation by providing more high level functions.
Fix a bug where we would assume that ARGB means
Format_ARGB32_Premultiplied and not Format_ARGB32.
Reviewed-by: Tom Cooksey
Diffstat (limited to 'src/plugins')
6 files changed, 327 insertions, 217 deletions
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp index 8a30ad4..8dbad53 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp @@ -64,8 +64,6 @@ void QDirectFBPaintDevice::lockDirectFB() { void *mem; int w, h; - DFBSurfacePixelFormat format; - DFBResult result = dfbSurface->Lock(dfbSurface, DSLF_WRITE, &mem, &bpl); if (result != DFB_OK || !mem) { DirectFBError("QDirectFBPixmapData::buffer()", result); @@ -73,10 +71,8 @@ void QDirectFBPaintDevice::lockDirectFB() { } dfbSurface->GetSize(dfbSurface, &w, &h); - dfbSurface->GetPixelFormat(dfbSurface, &format); - lockedImage = new QImage(static_cast<uchar*>(mem), w, h, bpl, - QDirectFBScreen::getImageFormat(format)); + QDirectFBScreen::getImageFormat(dfbSurface)); } @@ -102,9 +98,7 @@ void* QDirectFBPaintDevice::memory() const QImage::Format QDirectFBPaintDevice::format() const { - DFBSurfacePixelFormat dfbFormat; - dfbSurface->GetPixelFormat(dfbSurface, &dfbFormat); - return QDirectFBScreen::getImageFormat(dfbFormat); + return QDirectFBScreen::getImageFormat(dfbSurface); } diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index 86357e6..84a92d8 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -112,7 +112,7 @@ CachedImage::CachedImage(const QImage &image) description = QDirectFBScreen::getSurfaceDescription(image); QDirectFBScreen* screen = QDirectFBScreen::instance(); - tmpSurface = screen->createDFBSurface(&description); + tmpSurface = screen->createDFBSurface(&description, QDirectFBScreen::TrackSurface); if (!tmpSurface) { qWarning("CachedImage CreateSurface failed!"); return; @@ -124,7 +124,7 @@ CachedImage::CachedImage(const QImage &image) description.flags = DFBSurfaceDescriptionFlags(description.flags & ~DSDESC_PREALLOCATED); - s = screen->createDFBSurface(&description); + s = screen->createDFBSurface(&description, QDirectFBScreen::TrackSurface); if (!s) qWarning("QDirectFBPaintEngine failed caching image"); @@ -159,7 +159,7 @@ IDirectFBSurface* SurfaceCache::getSurface(const uint *buf, int size) DFBSurfaceDescription description; description = QDirectFBScreen::getSurfaceDescription(buf, size); - surface = QDirectFBScreen::instance()->createDFBSurface(&description); + surface = QDirectFBScreen::instance()->createDFBSurface(&description, QDirectFBScreen::TrackSurface); if (!surface) qWarning("QDirectFBPaintEngine: SurfaceCache: Unable to create surface"); @@ -724,13 +724,10 @@ void QDirectFBPaintEnginePrivate::drawImage(const QRectF &dest, const QRectF &src) { QImage image = srcImage; - if (QDirectFBScreen::getSurfacePixelFormat(image) == DSPF_UNKNOWN) { - QImage::Format format; - if (image.hasAlphaChannel()) - format = QImage::Format_ARGB32_Premultiplied; - else - format = QImage::Format_RGB32; - image = image.convertToFormat(format); + if (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN) { + image = image.convertToFormat(image.hasAlphaChannel() + ? QDirectFBScreen::instance()->alphaPixmapFormat() + : QDirectFBScreen::instance()->pixelFormat()); } CachedImage *img = imageCache[image.cacheKey()]; @@ -756,7 +753,8 @@ void QDirectFBPaintEnginePrivate::drawImage(const QRectF &dest, DFBSurfaceDescription description; description = QDirectFBScreen::getSurfaceDescription(image); - imgSurface = QDirectFBScreen::instance()->createDFBSurface(&description); + imgSurface = QDirectFBScreen::instance()->createDFBSurface(&description, + QDirectFBScreen::DontTrackSurface); if (!imgSurface) { qWarning("QDirectFBPaintEnginePrivate::drawImage"); return; @@ -790,8 +788,10 @@ void QDirectFBPaintEnginePrivate::drawImage(const QRectF &dest, } if (changeFlags) surface->SetBlittingFlags(surface, DFBSurfaceBlittingFlags(blitFlags)); - if (doRelease) - QDirectFBScreen::instance()->releaseDFBSurface(imgSurface); + if (doRelease) { + surface->ReleaseSource(surface); + imgSurface->Release(imgSurface); + } } void QDirectFBPaintEnginePrivate::updateClip() @@ -1092,11 +1092,11 @@ void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r, QRasterPaintEngine::drawTiledPixmap(r, pixmap, sp); } else if (!d->dfbCanHandleClip(r) || d->matrixRotShear || !sp.isNull()) { - QImage* img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(); + const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(); + d->lock(); QRasterPixmapData *data = new QRasterPixmapData(QPixmapData::PixmapType); data->fromImage(*img, Qt::AutoColor); const QPixmap pix(data); - d->lock(); QRasterPaintEngine::drawTiledPixmap(r, pix, sp); } else { diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp index 6352652..6d942a4 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp @@ -72,14 +72,19 @@ void QDirectFBPixmapData::resize(int width, int height) } DFBSurfaceDescription description; - description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | - DSDESC_HEIGHT); + description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH + | DSDESC_HEIGHT + | DSDESC_PIXELFORMAT); + QDirectFBScreen::initSurfaceDescriptionPixelFormat(&description, screen->pixelFormat()); description.width = width; description.height = height; - dfbSurface = screen->createDFBSurface(&description); - if (!dfbSurface) - qCritical("QDirectFBPixmapData::resize(): Unable to allocate surface"); + dfbSurface = screen->createDFBSurface(&description, QDirectFBScreen::TrackSurface); + if (!dfbSurface) { + setSerialNumber(0); + qWarning("QDirectFBPixmapData::resize(): Unable to allocate surface"); + return; + } setSerialNumber(++global_ser_no); } @@ -87,61 +92,15 @@ void QDirectFBPixmapData::resize(int width, int height) void QDirectFBPixmapData::fromImage(const QImage &img, Qt::ImageConversionFlags) { - QImage image; - if (QDirectFBScreen::getSurfacePixelFormat(img) == DSPF_UNKNOWN) - image = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); - else - image = img; - - DFBSurfaceDescription description; - description = QDirectFBScreen::getSurfaceDescription(image); - -#ifndef QT_NO_DIRECTFB_PREALLOCATED - IDirectFBSurface *imgSurface; - imgSurface = screen->createDFBSurface(&description); - if (!imgSurface) { - qWarning("QDirectFBPixmapData::fromImage()"); - setSerialNumber(0); - return; - } -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(imgSurface, image); -#endif -#endif // QT_NO_DIRECTFB_PREALLOCATED - - description.flags = DFBSurfaceDescriptionFlags(description.flags - & ~DSDESC_PREALLOCATED); - dfbSurface = screen->createDFBSurface(&description); + dfbSurface = screen->copyToDFBSurface(img, + img.hasAlphaChannel() ? screen->alphaPixmapFormat() + : screen->pixelFormat(), + QDirectFBScreen::TrackSurface); if (!dfbSurface) { qWarning("QDirectFBPixmapData::fromImage()"); setSerialNumber(0); return; } - -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(dfbSurface, image); -#endif - -#ifdef QT_NO_DIRECTFB_PREALLOCATED - char *mem; - surface->Lock(surface, DSLF_WRITE, (void**)&mem, &bpl); - const int w = image.width() * image.depth() / 8; - for (int i = 0; i < image.height(); ++i) { - memcpy(mem, image.scanLine(i), w); - mem += bpl; - } - surface->Unlock(surface); -#else - DFBResult result; - dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); - result = dfbSurface->Blit(dfbSurface, imgSurface, 0, 0, 0); - if (result != DFB_OK) - DirectFBError("QDirectFBPixmapData::fromImage()", result); - dfbSurface->Flip(dfbSurface, 0, DSFLIP_NONE); - dfbSurface->ReleaseSource(dfbSurface); - screen->releaseDFBSurface(imgSurface); -#endif // QT_NO_DIRECTFB_PREALLOCATED - setSerialNumber(++global_ser_no); } @@ -161,30 +120,24 @@ void QDirectFBPixmapData::copy(const QPixmapData *data, const QRect &rect) description.width = rect.width(); description.height = rect.height(); src->GetPixelFormat(src, &description.pixelformat); + src->GetCapabilities(src, &description.caps); - dfbSurface = screen->createDFBSurface(&description); + dfbSurface = screen->createDFBSurface(&description, QDirectFBScreen::TrackSurface); if (!dfbSurface) { qWarning("QDirectFBPixmapData::copy()"); setSerialNumber(0); return; } - DFBResult result; -#ifndef QT_NO_DIRECTFB_PALETTE - IDirectFBPalette *palette; - result = src->GetPalette(src, &palette); - if (result == DFB_OK) { - dfbSurface->SetPalette(dfbSurface, palette); - palette->Release(palette); - } -#endif - dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); const DFBRectangle blitRect = { rect.x(), rect.y(), rect.width(), rect.height() }; - result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0); - if (result != DFB_OK) + DFBResult result = dfbSurface->Blit(dfbSurface, src, &blitRect, 0, 0); + if (result != DFB_OK) { DirectFBError("QDirectFBPixmapData::copy()", result); + setSerialNumber(0); + return; + } setSerialNumber(++global_ser_no); } @@ -198,37 +151,16 @@ void QDirectFBPixmapData::fill(const QColor &color) Q_ASSERT(dfbSurface); if (color.alpha() < 255 && !hasAlphaChannel()) { - // convert to surface supporting alpha channel - DFBSurfacePixelFormat format; - dfbSurface->GetPixelFormat(dfbSurface, &format); - switch (format) { - case DSPF_YUY2: - case DSPF_UYVY: - format = DSPF_AYUV; - break; -#if (Q_DIRECTFB_VERSION >= 0x010100) - case DSPF_RGB444: - format = DSPF_ARGB4444; - break; - case DSPF_RGB555: -#endif - case DSPF_RGB18: - format = DSPF_ARGB6666; - break; - default: - format = DSPF_ARGB; - break; - } - DFBSurfaceDescription description; description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT); dfbSurface->GetSize(dfbSurface, &description.width, &description.height); - description.pixelformat = format; + QDirectFBScreen::initSurfaceDescriptionPixelFormat(&description, screen->alphaPixmapFormat()); screen->releaseDFBSurface(dfbSurface); // release old surface - dfbSurface = screen->createDFBSurface(&description); + dfbSurface = screen->createDFBSurface(&description, QDirectFBScreen::TrackSurface); + setSerialNumber(++global_ser_no); if (!dfbSurface) { qWarning("QDirectFBPixmapData::fill()"); setSerialNumber(0); @@ -245,6 +177,10 @@ bool QDirectFBPixmapData::hasAlphaChannel() const if (!serialNumber()) return false; + // 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() + DFBSurfacePixelFormat format; dfbSurface->GetPixelFormat(dfbSurface, &format); switch (format) { @@ -274,14 +210,12 @@ QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, { QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); const QImage *image = that->buffer(); - if (image) { // avoid deep copy - const QImage transformed = image->transformed(transform, mode); - that->unlockDirectFB(); - QDirectFBPixmapData *data = new QDirectFBPixmapData(pixelType()); - data->fromImage(transformed, Qt::AutoColor); - return QPixmap(data); - } - return QPixmapData::transformed(transform, mode); + Q_ASSERT(image); + const QImage transformed = image->transformed(transform, mode); + that->unlockDirectFB(); + QDirectFBPixmapData *data = new QDirectFBPixmapData(QPixmapData::PixmapType); + data->fromImage(transformed, Qt::AutoColor); + return QPixmap(data); } int w, h; @@ -291,15 +225,14 @@ QPixmap QDirectFBPixmapData::transformed(const QTransform &transform, if (size.isEmpty()) return QPixmap(); - QDirectFBPixmapData *data = new QDirectFBPixmapData(pixelType()); + QDirectFBPixmapData *data = new QDirectFBPixmapData(QPixmapData::PixmapType); data->resize(size.width(), size.height()); IDirectFBSurface *dest = data->dfbSurface; dest->SetBlittingFlags(dest, DSBLIT_NOFX); - const DFBRectangle srcRect = { 0, 0, w, h }; const DFBRectangle destRect = { 0, 0, size.width(), size.height() }; - dest->StretchBlit(dest, dfbSurface, &srcRect, &destRect); + dest->StretchBlit(dest, dfbSurface, 0, &destRect); return QPixmap(data); } @@ -309,39 +242,9 @@ QImage QDirectFBPixmapData::toImage() const if (!dfbSurface) return QImage(); -#ifdef QT_NO_DIRECTFB_PREALLOCATED QDirectFBPixmapData *that = const_cast<QDirectFBPixmapData*>(this); const QImage *img = that->buffer(); - const QImage copied = img->copy(); - that->unlockDirectFB(); - return copied; -#else - - int w, h; - dfbSurface->GetSize(dfbSurface, &w, &h); - - // Always convert to ARGB32: - QImage image(w, h, QImage::Format_ARGB32); - - DFBSurfaceDescription description; - description = QDirectFBScreen::getSurfaceDescription(image); - - IDirectFBSurface *imgSurface = screen->createDFBSurface(&description); - if (!imgSurface) { - qWarning("QDirectFBPixmapData::toImage()"); - return QImage(); - } - - imgSurface->SetBlittingFlags(imgSurface, DSBLIT_NOFX); - DFBResult result = imgSurface->Blit(imgSurface, dfbSurface, 0, 0, 0); - if (result != DFB_OK) { - DirectFBError("QDirectFBPixmapData::toImage() blit failed", result); - return QImage(); - } - screen->releaseDFBSurface(imgSurface); - - return image; -#endif // QT_NO_DIRECTFB_PREALLOCATED + return img->copy(); } QPaintEngine* QDirectFBPixmapData::paintEngine() const diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp index 26c023f..db9672a 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp @@ -81,6 +81,7 @@ public: QDirectFBKeyboardHandler *keyboard; #endif bool videoonly; + QImage::Format alphaPixmapFormat; }; QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen* screen) @@ -96,6 +97,7 @@ QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen* screen) , keyboard(0) #endif , videoonly(false) + , alphaPixmapFormat(QImage::Format_Invalid) { #ifndef QT_NO_QWS_SIGNALHANDLER QWSSignalHandler::instance()->addObject(this); @@ -130,7 +132,80 @@ QDirectFBScreenPrivate::~QDirectFBScreenPrivate() dfb->Release(dfb); } -IDirectFBSurface* QDirectFBScreen::createDFBSurface(const DFBSurfaceDescription* desc, bool track) + + +// creates a preallocated surface with the same format as the image if +// possible. + +IDirectFBSurface* QDirectFBScreen::createDFBSurface(const QImage &img, SurfaceCreationOptions options) +{ + if (img.isNull()) // assert? + return 0; + if (QDirectFBScreen::getSurfacePixelFormat(img.format()) == DSPF_UNKNOWN) { + QImage image = img.convertToFormat(img.hasAlphaChannel() + ? d_ptr->alphaPixmapFormat + : pixelFormat()); + IDirectFBSurface *tmp = createDFBSurface(image, false); + if (!tmp) { + qWarning("Couldn't create surface createDFBSurface(QImage, bool)"); + return 0; + } + IDirectFBSurface *surface = copyDFBSurface(tmp, image.format(), options); + tmp->Release(tmp); + return surface; + } + + DFBSurfaceDescription desc = QDirectFBScreen::getSurfaceDescription(img); + IDirectFBSurface *surface = createDFBSurface(&desc, options); +#ifdef QT_NO_DIRECTFB_PREALLOCATED + if (surface) { + char *mem; + int bpl; + surface->Lock(dfbSurface, DSLF_WRITE, (void**)&mem, &bpl); + const int h = img.height(); + for (int i = 0; i < h; ++i) { + memcpy(mem, img.scanLine(i), bpl); + mem += bpl; + } + surface->Unlock(ret); + } +#endif +#ifndef QT_NO_DIRECTFB_PALETTE + if (img.numColors() != 0) + QDirectFBScreen::setSurfaceColorTable(surface, img); +#endif + return surface; +} + +IDirectFBSurface *QDirectFBScreen::copyDFBSurface(IDirectFBSurface *src, + QImage::Format format, + SurfaceCreationOptions options) +{ + Q_ASSERT(src); + QSize size; + src->GetSize(src, &size.rwidth(), &size.rheight()); + IDirectFBSurface *surface = createDFBSurface(size, format, options); + surface->SetBlittingFlags(surface, DSBLIT_NOFX); + surface->Blit(surface, src, 0, 0, 0); + surface->ReleaseSource(surface); // ??? Is this always right? + return surface; +} + +IDirectFBSurface *QDirectFBScreen::createDFBSurface(const QSize &size, + QImage::Format format, + SurfaceCreationOptions options) +{ + DFBSurfaceDescription desc; + desc.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH|DSDESC_HEIGHT); + if (!QDirectFBScreen::initSurfaceDescriptionPixelFormat(&desc, format)) + return 0; + desc.width = size.width(); + desc.height = size.height(); + return createDFBSurface(&desc, options); +} + + +IDirectFBSurface* QDirectFBScreen::createDFBSurface(const DFBSurfaceDescription *desc, SurfaceCreationOptions options) { DFBResult result; IDirectFBSurface* newSurface = 0; @@ -152,13 +227,18 @@ IDirectFBSurface* QDirectFBScreen::createDFBSurface(const DFBSurfaceDescription* result = d_ptr->dfb->CreateSurface(d_ptr->dfb, desc, &newSurface); if (result != DFB_OK) { - DirectFBError("QDirectFBScreen::createDFBSurface", result); + qWarning("QDirectFBScreen::createDFBSurface() Failed!\n" + " Flags %0x Caps %0x width %d height %d pixelformat %0x %d preallocated %p %d\n%s", + desc->flags, desc->caps, desc->width, desc->height, + desc->pixelformat, DFB_PIXELFORMAT_INDEX(desc->pixelformat), + desc->preallocated[0].data, desc->preallocated[0].pitch, + DirectFBErrorString(result)); return 0; } Q_ASSERT(newSurface); - if (track) { + if (options & TrackSurface) { d_ptr->allocatedSurfaces.insert(newSurface); //qDebug("Created a new DirectFB surface at %p. New count = %d", @@ -168,8 +248,63 @@ IDirectFBSurface* QDirectFBScreen::createDFBSurface(const DFBSurfaceDescription* return newSurface; } -void QDirectFBScreen::releaseDFBSurface(IDirectFBSurface* surface) +IDirectFBSurface *QDirectFBScreen::copyToDFBSurface(const QImage &img, + QImage::Format format, + SurfaceCreationOptions options) { + QImage image = img; + const QImage::Format pixmapFormat = image.hasAlphaChannel() + ? QDirectFBScreen::alphaPixmapFormat() + : QDirectFBScreen::pixelFormat(); + + if (QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN +#ifdef QT_NO_DIRECTFB_PREALLOCATED + || image.format() != pixmapFormat +#endif + ) { + image = image.convertToFormat(pixmapFormat); + } + + + IDirectFBSurface *dfbSurface = createDFBSurface(img.size(), format, options); + if (!dfbSurface) { + qWarning("QDirectFBPixmapData::fromImage() Couldn't create surface"); + return 0; + } + +#ifndef QT_NO_DIRECTFB_PREALLOCATED + IDirectFBSurface *imgSurface = createDFBSurface(img, DontTrackSurface); + if (!imgSurface) { + qWarning("QDirectFBPixmapData::fromImage()"); + QDirectFBScreen::releaseDFBSurface(dfbSurface); + return 0; + } + Q_ASSERT(imgSurface); + DFBResult result; + dfbSurface->SetBlittingFlags(dfbSurface, DSBLIT_NOFX); + result = dfbSurface->Blit(dfbSurface, imgSurface, 0, 0, 0); + if (result != DFB_OK) + DirectFBError("QDirectFBPixmapData::fromImage()", result); + dfbSurface->ReleaseSource(dfbSurface); + imgSurface->Release(imgSurface); +#else // QT_NO_DIRECTFB_PREALLOCATED + Q_ASSERT(image.format() == pixmapFormat); + char *mem; + int bpl; + dfbSurface->Lock(dfbSurface, DSLF_WRITE, (void**)&mem, &bpl); + const int w = image.width() * image.depth() / 8; + for (int i = 0; i < image.height(); ++i) { + memcpy(mem, image.scanLine(i), w); + mem += bpl; + } + dfbSurface->Unlock(dfbSurface); +#endif + return dfbSurface; +} + +void QDirectFBScreen::releaseDFBSurface(IDirectFBSurface *surface) +{ + Q_ASSERT(QDirectFBScreen::instance()); Q_ASSERT(surface); surface->Release(surface); if (!d_ptr->allocatedSurfaces.remove(surface)) @@ -200,9 +335,9 @@ IDirectFBDisplayLayer* QDirectFBScreen::dfbDisplayLayer() } #endif -DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(const QImage &image) +DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(QImage::Format format) { - switch (image.format()) { + switch (format) { #ifndef QT_NO_DIRECTFB_PALETTE case QImage::Format_Indexed8: return DSPF_LUT8; @@ -233,8 +368,21 @@ DFBSurfacePixelFormat QDirectFBScreen::getSurfacePixelFormat(const QImage &image }; } -QImage::Format QDirectFBScreen::getImageFormat(DFBSurfacePixelFormat format) +static inline bool isPremultiplied(IDirectFBSurface *surface) +{ + Q_ASSERT(surface); + DFBSurfaceCapabilities caps; + const DFBResult result = surface->GetCapabilities(surface, &caps); + Q_ASSERT(result == DFB_OK); + Q_UNUSED(result); + return caps & DSCAPS_PREMULTIPLIED; +} + +QImage::Format QDirectFBScreen::getImageFormat(IDirectFBSurface *surface) { + DFBSurfacePixelFormat format; + surface->GetPixelFormat(surface, &format); + switch (format) { case DSPF_LUT8: return QImage::Format_Indexed8; @@ -257,8 +405,14 @@ QImage::Format QDirectFBScreen::getImageFormat(DFBSurfacePixelFormat format) return QImage::Format_RGB666; case DSPF_RGB32: return QImage::Format_RGB32; - case DSPF_ARGB: - return QImage::Format_ARGB32_Premultiplied; + case DSPF_ARGB: { + DFBSurfaceCapabilities caps; + const DFBResult result = surface->GetCapabilities(surface, &caps); + Q_ASSERT(result == DFB_OK); + Q_UNUSED(result); + return (caps & DSCAPS_PREMULTIPLIED + ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_ARGB32); } default: break; } @@ -268,38 +422,32 @@ QImage::Format QDirectFBScreen::getImageFormat(DFBSurfacePixelFormat format) DFBSurfaceDescription QDirectFBScreen::getSurfaceDescription(const QImage &image) { DFBSurfaceDescription description; - DFBSurfacePixelFormat format = getSurfacePixelFormat(image); + + const DFBSurfacePixelFormat format = getSurfacePixelFormat(image.format()); if (format == DSPF_UNKNOWN || image.isNull()) { description.flags = DFBSurfaceDescriptionFlags(0); return description; } - description.flags = DFBSurfaceDescriptionFlags(DSDESC_CAPS - | DSDESC_WIDTH + description.flags = DFBSurfaceDescriptionFlags(DSDESC_WIDTH | DSDESC_HEIGHT - | DSDESC_PIXELFORMAT - | DSDESC_PREALLOCATED); - - description.caps = DSCAPS_NONE; +#ifndef QT_NO_DIRECTFB_PREALLOCATED + | DSDESC_PREALLOCATED +#endif + | DSDESC_PIXELFORMAT); + QDirectFBScreen::initSurfaceDescriptionPixelFormat(&description, image.format()); description.width = image.width(); description.height = image.height(); - description.pixelformat = format; +#ifndef QT_NO_DIRECTFB_PREALLOCATED description.preallocated[0].data = (void*)(image.bits()); description.preallocated[0].pitch = image.bytesPerLine(); description.preallocated[1].data = 0; description.preallocated[1].pitch = 0; +#endif - switch (image.format()) { - case QImage::Format_ARGB32_Premultiplied: - case QImage::Format_ARGB8565_Premultiplied: - case QImage::Format_ARGB6666_Premultiplied: - case QImage::Format_ARGB8555_Premultiplied: - case QImage::Format_ARGB4444_Premultiplied: + if (QDirectFBScreen::isPremultiplied(image.format())) description.caps = DSCAPS_PREMULTIPLIED; - default: - break; - } return description; } @@ -337,7 +485,7 @@ void QDirectFBScreen::setSurfaceColorTable(IDirectFBSurface *surface, if (numColors == 0) return; - QVarLengthArray<DFBColor> colors(numColors); + QVarLengthArray<DFBColor, 256> colors(numColors); for (int i = 0; i < numColors; ++i) { QRgb c = image.color(i); colors[i].a = qAlpha(c); @@ -461,18 +609,10 @@ void QDirectFBScreenCursor::set(const QImage &image, int hotx, int hoty) } else if (!image.isNull() && implicitHide) { show(); } + cursor = image.convertToFormat(QDirectFBScreen::instance()->alphaPixmapFormat()); if (!image.isNull()) { -#ifdef QT_NO_DIRECTFB_PALETTE - if (image.numColors() > 0) - cursor = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); - else -#endif - if (image.format() == QImage::Format_Indexed8) { - cursor = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); - } else { - cursor = image; - } + Q_ASSERT(cursor.numColors() == 0); size = cursor.size(); hotspot = QPoint(hotx, hoty); @@ -480,15 +620,12 @@ void QDirectFBScreenCursor::set(const QImage &image, int hotx, int hoty) description = QDirectFBScreen::getSurfaceDescription(cursor); IDirectFBSurface *surface; - surface = QDirectFBScreen::instance()->createDFBSurface(&description); + surface = QDirectFBScreen::instance()->createDFBSurface(&description, + QDirectFBScreen::TrackSurface); if (!surface) { qWarning("QDirectFBScreenCursor::set: Unable to create surface"); return; } -#ifndef QT_NO_DIRECTFB_PALETTE - QDirectFBScreen::setSurfaceColorTable(surface, cursor); -#endif - DFBResult result = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE); if (result != DFB_OK) { DirectFBError("QDirectFBScreenCursor::set: " @@ -636,7 +773,7 @@ bool QDirectFBScreen::connect(const QString &displaySpec) } const QStringList displayArgs = displaySpec.split(QLatin1Char(':'), - QString::SkipEmptyParts); + QString::SkipEmptyParts); d_ptr->setFlipFlags(displayArgs); @@ -663,6 +800,12 @@ bool QDirectFBScreen::connect(const QString &displaySpec) description.caps = DFBSurfaceCapabilities(DSCAPS_PRIMARY | DSCAPS_DOUBLE | DSCAPS_STATIC_ALLOC); + if (displayArgs.contains(QLatin1String("forcepremultiplied"), + Qt::CaseInsensitive)) { + description.caps = DFBSurfaceCapabilities(description.caps + | DSCAPS_PREMULTIPLIED); + } + if (!(d_ptr->flipFlags & DSFLIP_BLIT)) { description.caps = DFBSurfaceCapabilities(description.caps | DSCAPS_DOUBLE @@ -671,12 +814,43 @@ bool QDirectFBScreen::connect(const QString &displaySpec) // We don't track the primary surface as it's released in disconnect - d_ptr->dfbSurface = createDFBSurface(&description, false); + d_ptr->dfbSurface = createDFBSurface(&description, DontTrackSurface); if (!d_ptr->dfbSurface) { DirectFBError("QDirectFBScreen: error creating primary surface", result); return false; } + + // Work out what format we're going to use for surfaces with an alpha channel + d_ptr->alphaPixmapFormat = QDirectFBScreen::getImageFormat(d_ptr->dfbSurface); + setPixelFormat(d_ptr->alphaPixmapFormat); + switch (d_ptr->alphaPixmapFormat) { + case QImage::Format_RGB666: + d_ptr->alphaPixmapFormat = QImage::Format_ARGB6666_Premultiplied; + break; + case QImage::Format_RGB444: + d_ptr->alphaPixmapFormat = QImage::Format_ARGB4444_Premultiplied; + break; + case QImage::NImageFormats: + case QImage::Format_Invalid: + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + case QImage::Format_Indexed8: + case QImage::Format_RGB32: + case QImage::Format_RGB888: + case QImage::Format_RGB16: + case QImage::Format_RGB555: + d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied; + break; + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + case QImage::Format_ARGB4444_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB6666_Premultiplied: + // works already + break; + } d_ptr->dfbSurface->GetSize(d_ptr->dfbSurface, &w, &h); data = 0; @@ -692,7 +866,7 @@ bool QDirectFBScreen::connect(const QString &displaySpec) else DirectFBError("QDirectFBScreen: error getting surface format", result); - setPixelFormat(getImageFormat(format)); + setPixelFormat(getImageFormat(d_ptr->dfbSurface)); physWidth = physHeight = -1; QRegExp mmWidthRx(QLatin1String("mmWidth=?(\\d+)")); @@ -954,21 +1128,14 @@ void QDirectFBScreen::exposeRegion(QRegion r, int changing) void QDirectFBScreen::blit(const QImage &img, const QPoint &topLeft, const QRegion ®) { - IDirectFBSurface *src = 0; - DFBSurfaceDescription description = getSurfaceDescription(img); - - src = createDFBSurface(&description); + IDirectFBSurface *src = createDFBSurface(img, QDirectFBScreen::DontTrackSurface); if (!src) { qWarning("QDirectFBScreen::blit(): Error creating surface"); return; } -#ifndef QT_NO_DIRECTFB_PALETTE - setSurfaceColorTable(d_ptr->dfbSurface, img); -#endif - blit(src, topLeft, reg); - - releaseDFBSurface(src); + d_ptr->dfbSurface->ReleaseSource(d_ptr->dfbSurface); + src->Release(src); } void QDirectFBScreen::blit(IDirectFBSurface *src, const QPoint &topLeft, @@ -1021,3 +1188,27 @@ void QDirectFBScreen::solidFill(const QColor &color, const QRegion ®ion) dfbRects.size()); } +QImage::Format QDirectFBScreen::alphaPixmapFormat() const +{ + return d_ptr->alphaPixmapFormat; +} + + +bool QDirectFBScreen::initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, + QImage::Format format) +{ + const DFBSurfacePixelFormat pixelformat = QDirectFBScreen::getSurfacePixelFormat(format); + if (pixelformat == DSPF_UNKNOWN) + return false; + description->flags = DFBSurfaceDescriptionFlags(description->flags | DSDESC_PIXELFORMAT); + description->pixelformat = pixelformat; + if (QDirectFBScreen::isPremultiplied(format)) { + if (!(description->flags & DSDESC_CAPS)) { + description->caps = DSCAPS_PREMULTIPLIED; + description->flags = DFBSurfaceDescriptionFlags(description->flags | DSDESC_CAPS); + } else { + description->caps = DFBSurfaceCapabilities(description->caps | DSCAPS_PREMULTIPLIED); + } + } + return true; +} diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h index 35dea0d..a1e93c6 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h +++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h @@ -88,18 +88,38 @@ public: #endif // Track surface creation/release so we can release all on exit - IDirectFBSurface* createDFBSurface(const DFBSurfaceDescription* desc, bool track = true); + enum SurfaceCreationOption { + DontTrackSurface = 0, + TrackSurface = 1 + }; + Q_DECLARE_FLAGS(SurfaceCreationOptions, SurfaceCreationOption); + IDirectFBSurface *createDFBSurface(const DFBSurfaceDescription *desc, + SurfaceCreationOptions options); + IDirectFBSurface *createDFBSurface(const QImage &image, + SurfaceCreationOptions options); + IDirectFBSurface *createDFBSurface(const QSize &size, + QImage::Format format, + SurfaceCreationOptions options); + IDirectFBSurface *copyDFBSurface(IDirectFBSurface *src, + QImage::Format format, + SurfaceCreationOptions options); + IDirectFBSurface *copyToDFBSurface(const QImage &image, + QImage::Format format, + SurfaceCreationOptions options); void releaseDFBSurface(IDirectFBSurface* surface); + bool preferVideoOnly() const; static int depth(DFBSurfacePixelFormat format); - static DFBSurfacePixelFormat getSurfacePixelFormat(const QImage &image); + static DFBSurfacePixelFormat getSurfacePixelFormat(QImage::Format format); static DFBSurfaceDescription getSurfaceDescription(const QImage &image); static DFBSurfaceDescription getSurfaceDescription(const uint *buffer, int length); - static QImage::Format getImageFormat(DFBSurfacePixelFormat format); + static QImage::Format getImageFormat(IDirectFBSurface *surface); + static bool initSurfaceDescriptionPixelFormat(DFBSurfaceDescription *description, QImage::Format format); static inline bool isPremultiplied(QImage::Format format); + QImage::Format alphaPixmapFormat() const; #ifndef QT_NO_DIRECTFB_PALETTE static void setSurfaceColorTable(IDirectFBSurface *surface, @@ -114,6 +134,8 @@ private: QDirectFBScreenPrivate *d_ptr; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QDirectFBScreen::SurfaceCreationOptions); + inline bool QDirectFBScreen::isPremultiplied(QImage::Format format) { switch (format) { diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp index ce026ea..00d1781 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbsurface.cpp @@ -153,8 +153,8 @@ void QDirectFBSurface::setGeometry(const QRect &rect, const QRegion &mask) DSDESC_PIXELFORMAT); description.width = rect.width(); description.height = rect.height(); - description.pixelformat = DSPF_ARGB; - + QDirectFBScreen::initSurfaceDescriptionPixelFormat(&description, + QDirectFBSurface::instance()->pixelFormat()); dfbSurface = QDirectFBScreen::instance()->createDFBSurface(&description, false); } else { Q_ASSERT(dfbSurface); |