void QGLPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::SgImage && pixmap) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); m_sgImage = new RSgImage; m_sgImage->Open(sgImage->Id()); TSgImageInfo info; sgImage->GetInfo(info); w = info.iSizeInPixels.iWidth; h = info.iSizeInPixels.iHeight; d = symbianPixeFormatBitsPerPixel((TUidPixelFormat)info.iPixelFormat); m_source = QVolatileImage(); m_hasAlpha = true; m_hasFillColor = false; m_dirty = true; is_null = (w <= 0 || h <= 0); #endif } else if (type == QPixmapData::FbsBitmap && pixmap) { CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap *>(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); } m_hasAlpha = m_source.hasAlphaChannel(); m_hasFillColor = false; m_dirty = true; d = m_source.depth(); } else if (type == QPixmapData::VolatileImage && pixmap) { // Support QS60Style in more efficient skin graphics retrieval. QVolatileImage *img = static_cast<QVolatileImage *>(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; d = m_source.depth(); } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { destroyTexture(); nativeImageHandleProvider = static_cast<QNativeImageHandleProvider *>(pixmap); // Cannot defer the retrieval, we need at least the size right away. createFromNativeImageHandleProvider(); } }
void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::SgImage && pixmap) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); destroyImages(); prevSize = QSize(); vgImage = sgImageToVGImage(context, *sgImage); if (vgImage != VG_INVALID_HANDLE) { w = vgGetParameteri(vgImage, VG_IMAGE_WIDTH); h = vgGetParameteri(vgImage, VG_IMAGE_HEIGHT); d = 32; // We always use ARGB_Premultiplied for VG pixmaps. } is_null = (w <= 0 || h <= 0); source = QVolatileImage(); // readback will be done later, only when needed recreate = false; prevSize = QSize(w, h); updateSerial(); #endif } else if (type == QPixmapData::FbsBitmap && pixmap) { CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap *>(pixmap); QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); resize(size.width(), size.height()); source = QVolatileImage(bitmap); // duplicates only, if possible if (source.isNull()) return; if (!conversionLessFormat(source.format())) { // Here we may need to copy if the formats do not match. // (e.g. for display modes other than EColor16MAP and EColor16MU) source.beginDataAccess(); QImage::Format format = idealFormat(&source.imageRef(), Qt::AutoColor); source.endDataAccess(true); source.ensureFormat(format); } recreate = true; } else if (type == QPixmapData::VolatileImage && pixmap) { QVolatileImage *img = static_cast<QVolatileImage *>(pixmap); resize(img->width(), img->height()); source = *img; recreate = true; } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { destroyImages(); nativeImageHandleProvider = static_cast<QNativeImageHandleProvider *>(pixmap); // Cannot defer the retrieval, we need at least the size right away. createFromNativeImageHandleProvider(); } }
// If copyBack is true, bind will copy the contents of the render // FBO to the texture (which is not bound to the texture, as it's // a multisample FBO). GLuint QGLPixmapData::bind(bool copyBack) const { if (m_renderFbo && copyBack) { copyBackFromRenderFbo(true); } else { ensureCreated(); } GLuint id = m_texture.id; glBindTexture(GL_TEXTURE_2D, id); if (m_hasFillColor) { if (!useFramebufferObjects()) { m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); m_source.fill(PREMUL(m_fillColor.rgba())); } m_hasFillColor = false; 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.constBits()); } return id; }
bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, Qt::ImageConversionFlags flags) { bool alpha; const char *buf = reinterpret_cast<const char *>(buffer); if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) { resize(0, 0); QGLShareContextScope ctx(qt_gl_share_widget()->context()); QSize size = m_texture.bindCompressedTexture(buf, int(len), format); if (!size.isEmpty()) { w = size.width(); h = size.height(); is_null = false; d = 32; m_hasAlpha = alpha; m_source = QVolatileImage(); m_dirty = isValid(); return true; } } QByteArray a = QByteArray::fromRawData(reinterpret_cast<const char *>(buffer), len); QBuffer b(&a); b.open(QIODevice::ReadOnly); QImage image = QImageReader(&b, format).read(); if (image.isNull()) return false; createPixmapForImage(image, flags, true); return !isNull(); }
void QVGPixmapData::ensureReadback(bool readOnly) const { if (vgImage != VG_INVALID_HANDLE && source.isNull()) { source = QVolatileImage(w, h, sourceFormat()); source.beginDataAccess(); vgGetImageSubData(vgImage, source.bits(), source.bytesPerLine(), qt_vg_image_to_vg_format(source.format()), 0, 0, w, h); source.endDataAccess(); if (readOnly) { recreate = false; } else { // Once we did a readback, the original VGImage must be destroyed // because it may be shared (e.g. created via SgImage) and a subsequent // upload of the image data may produce unexpected results. const_cast<QVGPixmapData *>(this)->destroyImages(); #if defined(Q_OS_SYMBIAN) // There is now an own copy of the data so drop the handle provider, // otherwise toVGImage() would request the handle again, which is wrong. nativeImageHandleProvider = 0; #endif recreate = true; } } }
void QGLPixmapData::fill(const QColor &color) { if (!isValid()) return; bool hasAlpha = color.alpha() != 255; if (hasAlpha && !m_hasAlpha) { if (m_texture.id) { destroyTexture(); m_dirty = true; } m_hasAlpha = color.alpha() != 255; } if (useFramebufferObjects()) { m_source = QVolatileImage(); m_hasFillColor = true; m_fillColor = color; } else { forceToImage(); if (m_source.depth() == 32) { m_source.fill(PREMUL(color.rgba())); } else if (m_source.depth() == 1) { if (color == Qt::color1) m_source.fill(1); else m_source.fill(0); } } }
void tst_QVolatileImage::create() { QVolatileImage nullImg; QVERIFY(nullImg.isNull()); QVolatileImage img(100, 200, QImage::Format_ARGB32); QVERIFY(!img.isNull()); QCOMPARE(img.width(), 100); QCOMPARE(img.height(), 200); QCOMPARE(img.format(), QImage::Format_ARGB32); QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); QCOMPARE(img.hasAlphaChannel(), true); QCOMPARE(img.depth(), 32); QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); img = QVolatileImage(source); QVERIFY(!img.isNull()); QCOMPARE(img.width(), 12); QCOMPARE(img.height(), 23); QCOMPARE(img.format(), source.format()); QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); QVERIFY(img.imageRef() == source); QVERIFY(img.toImage() == source); QCOMPARE(img.hasAlphaChannel(), true); QCOMPARE(img.hasAlphaChannel(), img.imageRef().hasAlphaChannel()); QCOMPARE(img.hasAlphaChannel(), img.toImage().hasAlphaChannel()); QCOMPARE(img.depth(), 32); }
void* QGLPixmapData::toNativeType(NativeType type) { if (type == QPixmapData::FbsBitmap) { if (m_source.isNull()) m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); return m_source.duplicateNativeImage(); } return 0; }
void QVGPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) { resize(image.width(), image.height()); QImage::Format format = idealFormat(&image, flags); if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { source = QVolatileImage(image); } else { QImage convertedImage = image.convertToFormat(format); // convertToFormat won't detach the image if format stays the // same. Detaching is needed to prevent issues with painting // onto this QPixmap later on. convertedImage.detach(); source = QVolatileImage(convertedImage); } recreate = true; }
QImage QVGPixmapData::toImage() const { if (!isValid()) return QImage(); ensureReadback(true); if (source.isNull()) { source = QVolatileImage(w, h, sourceFormat()); recreate = true; } return source.toImage(); }
void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) { if (image.size() == QSize(w, h)) setSerialNumber(++qt_gl_pixmap_serial); resize(image.width(), image.height()); if (pixelType() == BitmapType) { QImage convertedImage = image.convertToFormat(QImage::Format_MonoLSB); if (image.format() == QImage::Format_MonoLSB) convertedImage.detach(); m_source = QVolatileImage(convertedImage); } else { QImage::Format format = idealFormat(image, flags); if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { m_source = QVolatileImage(image); } else { QImage convertedImage = image.convertToFormat(format); // convertToFormat won't detach the image if format stays the same. if (image.format() == format) convertedImage.detach(); m_source = QVolatileImage(convertedImage); } } m_dirty = true; m_hasFillColor = false; m_hasAlpha = m_source.hasAlphaChannel(); w = image.width(); h = image.height(); is_null = (w <= 0 || h <= 0); d = m_source.depth(); destroyTexture(); }
// Ensures that the pixmap is backed by some valid data and forces the data to // be re-uploaded to the VGImage when toVGImage() is called next time. void QVGPixmapData::forceToImage(bool allowReadback) { if (!isValid()) return; if (allowReadback) ensureReadback(false); if (source.isNull()) source = QVolatileImage(w, h, sourceFormat()); recreate = true; }
// Force the pixmap data to be backed by some valid data. void QGLPixmapData::forceToImage() { if (!isValid()) return; 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; }
void QVGPixmapData::resize(int wid, int ht) { if (w == wid && h == ht) { updateSerial(); return; } w = wid; h = ht; d = 32; // We always use ARGB_Premultiplied for VG pixmaps. is_null = (w <= 0 || h <= 0); source = QVolatileImage(); recreate = true; updateSerial(); }
void tst_QVolatileImage::dataAccess() { QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); QVolatileImage img(source); QVERIFY(!img.isNull()); img.beginDataAccess(); QVERIFY(img.constBits()); QVERIFY(img.imageRef().constBits()); QVERIFY(img.bits()); QVERIFY(img.imageRef().bits()); img.endDataAccess(); img = QVolatileImage(12, 23, QImage::Format_ARGB32); img.beginDataAccess(); QVERIFY(img.constBits() && img.bits()); img.endDataAccess(); }
void tst_QVolatileImage::create() { QVolatileImage nullImg; QVERIFY(nullImg.isNull()); QVolatileImage img(100, 200, QImage::Format_ARGB32); QVERIFY(!img.isNull()); QCOMPARE(img.width(), 100); QCOMPARE(img.height(), 200); QCOMPARE(img.format(), QImage::Format_ARGB32); QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); QCOMPARE(img.hasAlphaChannel(), true); QCOMPARE(img.depth(), 32); QImage source(12, 23, QImage::Format_ARGB32_Premultiplied); img = QVolatileImage(source); QVERIFY(!img.isNull()); QCOMPARE(img.width(), 12); QCOMPARE(img.height(), 23); QCOMPARE(img.format(), source.format()); QCOMPARE(img.byteCount(), img.bytesPerLine() * img.height()); QVERIFY(img.imageRef() == source); QVERIFY(img.toImage() == source); QCOMPARE(img.hasAlphaChannel(), true); QCOMPARE(img.hasAlphaChannel(), img.imageRef().hasAlphaChannel()); QCOMPARE(img.hasAlphaChannel(), img.toImage().hasAlphaChannel()); QCOMPARE(img.depth(), 32); #ifdef Q_OS_SYMBIAN CFbsBitmap *bmp = new CFbsBitmap; QVERIFY(bmp->Create(TSize(100, 50), EColor16MAP) == KErrNone); QVolatileImage bmpimg(bmp); QVERIFY(!bmpimg.isNull()); QCOMPARE(bmpimg.width(), 100); QCOMPARE(bmpimg.height(), 50); // Verify that we only did handle duplication, not pixel data copying. QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); delete bmp; // Check if content is still valid. QImage copyimg = bmpimg.toImage(); QCOMPARE(copyimg.format(), QImage::Format_ARGB32_Premultiplied); #endif }
void QGLPixmapData::resize(int width, int height) { if (width == w && height == h) return; if (width <= 0 || height <= 0) { width = 0; height = 0; } w = width; h = height; is_null = (w <= 0 || h <= 0); d = pixelType() == QPixmapData::PixmapType ? 32 : 1; destroyTexture(); m_source = QVolatileImage(); m_dirty = isValid(); setSerialNumber(++qt_gl_pixmap_serial); }
bool QGLPixmapData::fromFile(const QString &filename, const char *format, Qt::ImageConversionFlags flags) { if (pixelType() == QPixmapData::BitmapType) return QPixmapData::fromFile(filename, format, flags); QFile file(filename); if (file.open(QIODevice::ReadOnly)) { QByteArray data = file.peek(64); bool alpha; if (m_texture.canBindCompressedTexture (data.constData(), data.size(), format, &alpha)) { resize(0, 0); data = file.readAll(); file.close(); QGLShareContextScope ctx(qt_gl_share_widget()->context()); QSize size = m_texture.bindCompressedTexture (data.constData(), data.size(), format); if (!size.isEmpty()) { w = size.width(); h = size.height(); is_null = false; d = 32; m_hasAlpha = alpha; m_source = QVolatileImage(); m_dirty = isValid(); return true; } return false; } } QImage image = QImageReader(filename, format).read(); if (image.isNull()) return false; createPixmapForImage(image, flags, true); return !isNull(); }
void QVGPixmapData::copy(const QPixmapData *data, const QRect &rect) { // toImage() is potentially expensive with QVolatileImage so provide a // more efficient implementation of copy() that does not rely on it. if (!data) { return; } if (data->classId() != OpenVGClass) { fromImage(data->toImage(rect), Qt::NoOpaqueDetection); return; } const QVGPixmapData *pd = static_cast<const QVGPixmapData *>(data); QRect r = rect; if (r.isNull() || r.contains(QRect(0, 0, pd->w, pd->h))) { r = QRect(0, 0, pd->w, pd->h); } resize(r.width(), r.height()); recreate = true; if (!pd->source.isNull()) { source = QVolatileImage(r.width(), r.height(), pd->source.format()); source.copyFrom(&pd->source, r); } }
void tst_QVolatileImage::copy() { QVolatileImage img(100, 100, QImage::Format_RGB32); img.beginDataAccess(); img.imageRef().fill(QColor(Qt::green).rgba()); QPainter p(&img.imageRef()); p.drawRect(10, 10, 50, 50); p.end(); img.endDataAccess(); QVolatileImage img2(100, 100, QImage::Format_RGB32); img2.copyFrom(&img, QRect()); QImage imgA = img.toImage(); QImage imgB = img2.toImage(); QCOMPARE(imgA.size(), imgB.size()); QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); img2 = QVolatileImage(20, 20, QImage::Format_RGB32); img2.copyFrom(&img, QRect(5, 5, 20, 20)); imgA = img.toImage().copy(5, 5, 20, 20); imgB = img2.toImage(); QCOMPARE(imgA.size(), imgB.size()); QVERIFY(fuzzyCompareImages(imgA, imgB, 0)); }
void* QVGPixmapData::toNativeType(NativeType type) { if (type == QPixmapData::SgImage) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) toVGImage(); if (!isValid() || vgImage == VG_INVALID_HANDLE) return 0; TInt err = 0; RSgDriver driver; err = driver.Open(); if (err != KErrNone) return 0; TSgImageInfo sgInfo; sgInfo.iPixelFormat = EUidPixelFormatARGB_8888_PRE; sgInfo.iSizeInPixels.SetSize(w, h); sgInfo.iUsage = ESgUsageBitOpenVgImage | ESgUsageBitOpenVgSurface; QScopedPointer<RSgImage> sgImage(new RSgImage()); err = sgImage->Create(sgInfo, NULL, NULL); if (err != KErrNone) { driver.Close(); return 0; } const EGLint KEglImageAttribs[] = {EGL_IMAGE_PRESERVED_SYMBIAN, EGL_TRUE, EGL_NONE}; EGLImageKHR eglImage = QEgl::eglCreateImageKHR(QEgl::display(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)sgImage.data(), (EGLint*)KEglImageAttribs); if (!eglImage || eglGetError() != EGL_SUCCESS) { sgImage->Close(); driver.Close(); return 0; } VGImage dstVgImage = QVG::vgCreateEGLImageTargetKHR(eglImage); if (!dstVgImage || vgGetError() != VG_NO_ERROR) { QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); sgImage->Close(); driver.Close(); return 0; } vgCopyImage(dstVgImage, 0, 0, vgImage, 0, 0, w, h, VG_FALSE); if (vgGetError() != VG_NO_ERROR) { sgImage->Close(); sgImage.reset(); } // release stuff vgDestroyImage(dstVgImage); QEgl::eglDestroyImageKHR(QEgl::display(), eglImage); driver.Close(); return reinterpret_cast<void*>(sgImage.take()); #endif } else if (type == QPixmapData::FbsBitmap && isValid()) { ensureReadback(true); if (source.isNull()) { source = QVolatileImage(w, h, sourceFormat()); } // Just duplicate the bitmap handle, no data copying happens. return source.duplicateNativeImage(); } return 0; }
void QVGPixmapData::cleanup() { is_null = w = h = 0; recreate = false; source = QVolatileImage(); }
void tst_QVolatileImage::bitmap() { #ifdef Q_OS_SYMBIAN CFbsBitmap *bmp = new CFbsBitmap; QVERIFY(bmp->Create(TSize(100, 50), EColor64K) == KErrNone); QVolatileImage bmpimg(bmp); CFbsBitmap *dupbmp = static_cast<CFbsBitmap *>(bmpimg.duplicateNativeImage()); QVERIFY(dupbmp); QVERIFY(dupbmp != bmp); QCOMPARE(dupbmp->DataAddress(), bmp->DataAddress()); delete dupbmp; delete bmp; bmpimg.beginDataAccess(); qMemSet(bmpimg.bits(), 0, bmpimg.byteCount()); qMemSet(bmpimg.bits(), 1, bmpimg.bytesPerLine() * bmpimg.height()); bmpimg.endDataAccess(); // Test bgr->rgb conversion in case of EColor16M. bmp = new CFbsBitmap; QVERIFY(bmp->Create(TSize(101, 89), EColor16M) == KErrNone); bmp->BeginDataAccess(); TUint32 *addr = bmp->DataAddress(); uint rgb = QColor(10, 20, 30).rgb(); qMemCopy(bmp->DataAddress(), &rgb, 3); bmp->EndDataAccess(); TRgb symrgb; bmp->GetPixel(symrgb, TPoint(0, 0)); QVERIFY(symrgb.Red() == 10 && symrgb.Green() == 20 && symrgb.Blue() == 30); bmpimg = QVolatileImage(bmp); QVERIFY(bmpimg.toImage().pixel(0, 0) == rgb); // check if there really was a conversion bmp->BeginDataAccess(); bmpimg.beginDataAccess(); qMemCopy(&rgb, bmpimg.constBits(), 3); uint rgb2 = rgb; qMemCopy(&rgb2, bmp->DataAddress(), 3); QVERIFY(rgb != rgb2); bmpimg.endDataAccess(true); bmp->EndDataAccess(true); delete bmp; bmp = new CFbsBitmap; QVERIFY(bmp->Create(TSize(101, 89), EGray2) == KErrNone); bmpimg = QVolatileImage(bmp); // inverts pixels, but should do it in place QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); QCOMPARE(bmpimg.format(), QImage::Format_MonoLSB); bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied); QVERIFY(bmpimg.constBits() != (const uchar *) bmp->DataAddress()); QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied); delete bmp; // The following two formats must be optimal always. bmp = new CFbsBitmap; QVERIFY(bmp->Create(TSize(101, 89), EColor16MAP) == KErrNone); bmpimg = QVolatileImage(bmp); QCOMPARE(bmpimg.format(), QImage::Format_ARGB32_Premultiplied); QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); bmpimg.ensureFormat(QImage::Format_ARGB32_Premultiplied); QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); delete bmp; bmp = new CFbsBitmap; QVERIFY(bmp->Create(TSize(101, 89), EColor16MU) == KErrNone); bmpimg = QVolatileImage(bmp); QCOMPARE(bmpimg.format(), QImage::Format_RGB32); QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); bmpimg.ensureFormat(QImage::Format_RGB32); QCOMPARE(bmpimg.constBits(), (const uchar *) bmp->DataAddress()); delete bmp; #else QSKIP("CFbsBitmap is only available on Symbian, skipping bitmap test", SkipSingle); #endif }
void QGLPixmapData::ensureCreated() const { if (!m_dirty) return; m_dirty = false; if (nativeImageHandleProvider && !nativeImageHandle) const_cast<QGLPixmapData *>(this)->createFromNativeImageHandleProvider(); QGLShareContextScope ctx(qt_gl_share_widget()->context()); m_ctx = ctx; const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB; #ifdef QT_OPENGL_ES_2 const GLenum external_format = internal_format; #else const GLenum external_format = qt_gl_preferredTextureFormat(); #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) { m_texture.id = QGLTexturePool::instance()->createTextureForPixmap( target, 0, internal_format, w, h, external_format, type, const_cast<QGLPixmapData*>(this)); if (!m_texture.id) { failedToAlloc = true; return; } glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); inTexturePool = true; } else if (inTexturePool) { glBindTexture(target, m_texture.id); QGLTexturePool::instance()->useTexture(const_cast<QGLPixmapData*>(this)); } if (!m_source.isNull() && m_texture.id) { if (external_format == GL_RGB) { 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); 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 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); 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 = QVolatileImage(); } }