From 9204b29b05cba62d64bf189d30b72b93f1693bbf Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 21 Mar 2011 13:33:08 +0200 Subject: Change the pooled QGLPixmapData to be backed by QVolatileImage. This change currently affects QGLPixmapData on Symbian only. Similarly to the OpenVG engine, using QVolatileImage allows more efficient handling of to- and fromSymbianCFbsBitmap, reduces local heap usage, and improves s60 style performance. Task-number: QTBUG-15252 Reviewed-by: Jani Hautakangas --- src/opengl/qgl_symbian.cpp | 140 +++++++++++------------------------- src/opengl/qpixmapdata_gl_p.h | 9 +++ src/opengl/qpixmapdata_poolgl.cpp | 118 +++++++++++++++++++----------- src/s60installs/bwins/QtOpenGLu.def | 1 + src/s60installs/eabi/QtOpenGLu.def | 1 + 5 files changed, 128 insertions(+), 141 deletions(-) diff --git a/src/opengl/qgl_symbian.cpp b/src/opengl/qgl_symbian.cpp index 2978514..78624a2 100644 --- a/src/opengl/qgl_symbian.cpp +++ b/src/opengl/qgl_symbian.cpp @@ -41,9 +41,7 @@ #include "qgl.h" -#include -#include -#include +#include #include #include #include @@ -72,6 +70,8 @@ QT_BEGIN_NAMESPACE #endif #endif +extern int qt_gl_pixmap_serial; + /* QGLTemporaryContext implementation */ @@ -361,117 +361,61 @@ void QGLWidgetPrivate::recreateEglSurface() eglSurfaceWindowId = currentId; } -/* - * Symbian specific QGLPixmapData functions - */ - -static CFbsBitmap* createBlitCopy(CFbsBitmap* bitmap) +static inline bool knownGoodFormat(QImage::Format format) { - CFbsBitmap *copy = q_check_ptr(new CFbsBitmap); - if (!copy) - return 0; - - if (copy->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) { - delete copy; - copy = 0; - - return 0; + switch (format) { + case QImage::Format_RGB16: // EColor64K + case QImage::Format_RGB32: // EColor16MU + case QImage::Format_ARGB32_Premultiplied: // EColor16MAP + return true; + default: + return false; } - - CFbsBitmapDevice* bitmapDevice = 0; - CFbsBitGc *bitmapGc = 0; - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(copy)); - QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); - bitmapGc->Activate(bitmapDevice); - - bitmapGc->BitBlt(TPoint(), bitmap); - - delete bitmapGc; - delete bitmapDevice; - - return copy; } void QGLPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = reinterpret_cast(pixmap); - - bool deleteSourceBitmap = false; -#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE - - // Rasterize extended bitmaps - - TUid extendedBitmapType = bitmap->ExtendedBitmapType(); - if (extendedBitmapType != KNullUid) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; - } -#endif - - if (bitmap->IsCompressedInRAM()) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; + CFbsBitmap *bitmap = reinterpret_cast(pixmap); + QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); + if (size.width() == w && size.height() == h) + setSerialNumber(++qt_gl_pixmap_serial); + resize(size.width(), size.height()); + m_source = QVolatileImage(bitmap); + if (pixelType() == BitmapType) { + m_source.ensureFormat(QImage::Format_MonoLSB); + } else if (!knownGoodFormat(m_source.format())) { + m_source.beginDataAccess(); + QImage::Format format = idealFormat(m_source.imageRef(), Qt::AutoColor); + m_source.endDataAccess(true); + m_source.ensureFormat(format); } - - TDisplayMode displayMode = bitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - - TSize size = bitmap->SizeInPixels(); - int bytesPerLine = bitmap->ScanLineLength(size.iWidth, displayMode); - - bitmap->BeginDataAccess(); - uchar *bytes = (uchar*)bitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format); - img = img.copy(); - bitmap->EndDataAccess(); - - if (displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - img.invertPixels(); - } else if (displayMode == EColor16M) { - img = img.rgbSwapped(); // EColor16M is BGR - } - - fromImage(img, Qt::AutoColor); - - if (deleteSourceBitmap) - delete bitmap; + m_hasAlpha = m_source.hasAlphaChannel(); + m_hasFillColor = false; + m_dirty = true; + + } else if (type == QPixmapData::VolatileImage && pixmap) { + // Support QS60Style in more efficient skin graphics retrieval. + QVolatileImage *img = static_cast(pixmap); + if (img->width() == w && img->height() == h) + setSerialNumber(++qt_gl_pixmap_serial); + resize(img->width(), img->height()); + m_source = *img; + m_hasAlpha = m_source.hasAlphaChannel(); + m_hasFillColor = false; + m_dirty = true; } } void* QGLPixmapData::toNativeType(NativeType type) { if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); - - if (bitmap) { - QImage image = toImage(); - - TDisplayMode displayMode(EColor16MU); - if (image.format()==QImage::Format_ARGB32_Premultiplied) - displayMode = EColor16MAP; - - if (bitmap->Create(TSize(image.width(), image.height()), - displayMode) == KErrNone) { - const uchar *sptr = const_cast(image).bits(); - bitmap->BeginDataAccess(); - - uchar *dptr = (uchar*)bitmap->DataAddress(); - Mem::Copy(dptr, sptr, image.byteCount()); - - bitmap->EndDataAccess(); - } else { - delete bitmap; - bitmap = 0; - } - } - - return reinterpret_cast(bitmap); + if (m_source.isNull()) + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); + return m_source.duplicateNativeImage(); } + return 0; } QT_END_NAMESPACE - diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index 55cc29d..41740dd 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -59,6 +59,10 @@ #include "private/qpixmapdata_p.h" #include "private/qglpaintdevice_p.h" +#ifdef Q_OS_SYMBIAN +#include "private/qvolatileimage_p.h" +#endif + QT_BEGIN_NAMESPACE class QPaintEngine; @@ -153,6 +157,7 @@ public: #endif #ifdef Q_OS_SYMBIAN + QImage::Format idealFormat(QImage &image, Qt::ImageConversionFlags flags); void* toNativeType(NativeType type); void fromNativeType(void* pixmap, NativeType type); #endif @@ -184,7 +189,11 @@ private: mutable QGLFramebufferObject *m_renderFbo; mutable QPaintEngine *m_engine; mutable QGLContext *m_ctx; +#ifdef Q_OS_SYMBIAN + mutable QVolatileImage m_source; +#else mutable QImage m_source; +#endif mutable QGLTexture m_texture; // the texture is not in sync with the source image diff --git a/src/opengl/qpixmapdata_poolgl.cpp b/src/opengl/qpixmapdata_poolgl.cpp index f1220b1..64de29e 100644 --- a/src/opengl/qpixmapdata_poolgl.cpp +++ b/src/opengl/qpixmapdata_poolgl.cpp @@ -247,7 +247,7 @@ void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) data = d; } -static int qt_gl_pixmap_serial = 0; +int qt_gl_pixmap_serial = 0; QGLPixmapData::QGLPixmapData(PixelType type) : QPixmapData(type, OpenGLClass) @@ -330,7 +330,7 @@ void QGLPixmapData::resize(int width, int height) destroyTexture(); - m_source = QImage(); + m_source = QVolatileImage(); m_dirty = isValid(); setSerialNumber(++qt_gl_pixmap_serial); } @@ -353,6 +353,11 @@ void QGLPixmapData::ensureCreated() const #endif const GLenum target = GL_TEXTURE_2D; + GLenum type = GL_UNSIGNED_BYTE; + // Avoid conversion when pixmap is created from CFbsBitmap of EColor64K. + if (!m_source.isNull() && m_source.format() == QImage::Format_RGB16) + type = GL_UNSIGNED_SHORT_5_6_5; + m_texture.options &= ~QGLContext::MemoryManagedBindOption; if (!m_texture.id) { @@ -361,7 +366,7 @@ void QGLPixmapData::ensureCreated() const 0, internal_format, w, h, external_format, - GL_UNSIGNED_BYTE, + type, const_cast(this)); if (!m_texture.id) { failedToAlloc = true; @@ -378,21 +383,35 @@ void QGLPixmapData::ensureCreated() const if (!m_source.isNull() && m_texture.id) { if (external_format == GL_RGB) { - const QImage tx = m_source.convertToFormat(QImage::Format_RGB888).mirrored(false, true); + m_source.beginDataAccess(); + QImage tx; + if (type == GL_UNSIGNED_BYTE) + tx = m_source.imageRef().convertToFormat(QImage::Format_RGB888).mirrored(false, true); + else if (type == GL_UNSIGNED_SHORT_5_6_5) + tx = m_source.imageRef().mirrored(false, true); + m_source.endDataAccess(true); glBindTexture(target, m_texture.id); - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, tx.bits()); + if (!tx.isNull()) + glTexSubImage2D(target, 0, 0, 0, w, h, external_format, + type, tx.constBits()); + else + qWarning("QGLPixmapData: Failed to create GL_RGB image of size %dx%d", w, h); } else { // do byte swizzling ARGB -> RGBA - const QImage tx = ctx->d_func()->convertToGLFormat(m_source, true, external_format); + m_source.beginDataAccess(); + const QImage tx = ctx->d_func()->convertToGLFormat(m_source.imageRef(), true, external_format); + m_source.endDataAccess(true); glBindTexture(target, m_texture.id); - glTexSubImage2D(target, 0, 0, 0, w, h, external_format, - GL_UNSIGNED_BYTE, tx.bits()); + if (!tx.isNull()) + glTexSubImage2D(target, 0, 0, 0, w, h, external_format, + type, tx.constBits()); + else + qWarning("QGLPixmapData: Failed to create GL_RGBA image of size %dx%d", w, h); } if (useFramebufferObjects()) - m_source = QImage(); + m_source = QVolatileImage(); } } @@ -437,7 +456,7 @@ bool QGLPixmapData::fromFile(const QString &filename, const char *format, is_null = false; d = 32; m_hasAlpha = alpha; - m_source = QImage(); + m_source = QVolatileImage(); m_dirty = isValid(); return true; } @@ -469,7 +488,7 @@ bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, is_null = false; d = 32; m_hasAlpha = alpha; - m_source = QImage(); + m_source = QVolatileImage(); m_dirty = isValid(); return true; } @@ -487,9 +506,20 @@ bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, return !isNull(); } -/*! - out-of-place conversion (inPlace == false) will always detach() - */ +QImage::Format QGLPixmapData::idealFormat(QImage &image, Qt::ImageConversionFlags flags) +{ + QImage::Format format = QImage::Format_RGB32; + if (qApp->desktop()->depth() == 16) + format = QImage::Format_RGB16; + + if (image.hasAlphaChannel() + && ((flags & Qt::NoOpaqueDetection) + || const_cast(image).data_ptr()->checkForAlphaPixels())) + format = QImage::Format_ARGB32_Premultiplied; + + return format; +} + void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) { if (image.size() == QSize(w, h)) @@ -498,26 +528,25 @@ void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags resize(image.width(), image.height()); if (pixelType() == BitmapType) { - m_source = image.convertToFormat(QImage::Format_MonoLSB); + QImage convertedImage = image.convertToFormat(QImage::Format_MonoLSB); + if (image.format() == QImage::Format_MonoLSB) + convertedImage.detach(); - } else { - QImage::Format format = QImage::Format_RGB32; - if (qApp->desktop()->depth() == 16) - format = QImage::Format_RGB16; + m_source = QVolatileImage(convertedImage); - if (image.hasAlphaChannel() - && ((flags & Qt::NoOpaqueDetection) - || const_cast(image).data_ptr()->checkForAlphaPixels())) - format = QImage::Format_ARGB32_Premultiplied; + } else { + QImage::Format format = idealFormat(image, flags); if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { - m_source = image; + m_source = QVolatileImage(image); } else { - m_source = image.convertToFormat(format); + QImage convertedImage = image.convertToFormat(format); // convertToFormat won't detach the image if format stays the same. if (image.format() == format) - m_source.detach(); + convertedImage.detach(); + + m_source = QVolatileImage(convertedImage); } } @@ -596,16 +625,13 @@ void QGLPixmapData::fill(const QColor &color) } if (useFramebufferObjects()) { - m_source = QImage(); + m_source = QVolatileImage(); m_hasFillColor = true; m_fillColor = color; } else { + forceToImage(); - if (m_source.isNull()) { - m_fillColor = color; - m_hasFillColor = true; - - } else if (m_source.depth() == 32) { + if (m_source.depth() == 32) { m_source.fill(PREMUL(color.rgba())); } else if (m_source.depth() == 1) { @@ -656,13 +682,15 @@ QImage QGLPixmapData::toImage() const if (m_renderFbo) { copyBackFromRenderFbo(true); } else if (!m_source.isNull()) { - QImageData *data = const_cast(m_source).data_ptr(); - if (data->paintEngine && data->paintEngine->isActive() - && data->paintEngine->paintDevice() == &m_source) - { - return m_source.copy(); + // QVolatileImage::toImage() will make a copy always so no check + // for active painting is needed. + QImage img = m_source.toImage(); + if (img.format() == QImage::Format_MonoLSB) { + img.setColorCount(2); + img.setColor(0, QColor(Qt::color0).rgba()); + img.setColor(1, QColor(Qt::color1).rgba()); } - return m_source; + return img; } else if (m_dirty || m_hasFillColor) { return fillImage(m_fillColor); } else { @@ -802,7 +830,7 @@ GLuint QGLPixmapData::bind(bool copyBack) const if (m_hasFillColor) { if (!useFramebufferObjects()) { - m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied); + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); m_source.fill(PREMUL(m_fillColor.rgba())); } @@ -811,7 +839,7 @@ GLuint QGLPixmapData::bind(bool copyBack) const GLenum format = qt_gl_preferredTextureFormat(); QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.bits()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.constBits()); } return id; @@ -888,8 +916,12 @@ void QGLPixmapData::forceToImage() if (!isValid()) return; - if (m_source.isNull()) - m_source = QImage(w, h, QImage::Format_ARGB32_Premultiplied); + if (m_source.isNull()) { + QImage::Format format = QImage::Format_ARGB32_Premultiplied; + if (pixelType() == BitmapType) + format = QImage::Format_MonoLSB; + m_source = QVolatileImage(w, h, format); + } m_dirty = true; } diff --git a/src/s60installs/bwins/QtOpenGLu.def b/src/s60installs/bwins/QtOpenGLu.def index 87d1b56..f52932c 100644 --- a/src/s60installs/bwins/QtOpenGLu.def +++ b/src/s60installs/bwins/QtOpenGLu.def @@ -718,4 +718,5 @@ EXPORTS ?releaseCachedResources@QGLGraphicsSystem@@UAEXXZ @ 717 NONAME ; void QGLGraphicsSystem::releaseCachedResources(void) ?serialNumber@QGLTextureGlyphCache@@QBEHXZ @ 718 NONAME ; int QGLTextureGlyphCache::serialNumber(void) const ?forceToImage@QGLPixmapData@@QAEXXZ @ 719 NONAME ; void QGLPixmapData::forceToImage(void) + ?idealFormat@QGLPixmapData@@QAE?AW4Format@QImage@@AAV3@V?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 720 NONAME ; enum QImage::Format QGLPixmapData::idealFormat(class QImage &, class QFlags) diff --git a/src/s60installs/eabi/QtOpenGLu.def b/src/s60installs/eabi/QtOpenGLu.def index 4c5dca9..f7a7f71 100644 --- a/src/s60installs/eabi/QtOpenGLu.def +++ b/src/s60installs/eabi/QtOpenGLu.def @@ -720,4 +720,5 @@ EXPORTS _ZN13QGLPixmapData21detachTextureFromPoolEv @ 719 NONAME _ZN13QGLPixmapData9hibernateEv @ 720 NONAME _ZN17QGLGraphicsSystem22releaseCachedResourcesEv @ 721 NONAME + _ZN13QGLPixmapData11idealFormatER6QImage6QFlagsIN2Qt19ImageConversionFlagEE @ 722 NONAME -- cgit v0.12