Do not byteswap RGBA8888 formats

The three RGBA8888 formats was introduced to make it possible to have
QImages and QPixmaps in native OpenGL formats, but uploaded textures of
these types are still converted to ARGB first and then swapped back.

This patch detects the formats and ensures the unneeded back-and-forth
conversion does not take place. It also replaces a seemingly unused
private API meant for the same goal.

Change-Id: Id69d6973bb9c13d1052f2a1b0c516183f63421c2
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
bb10
Allan Sandfeld Jensen 2013-10-24 19:50:34 +02:00 committed by The Qt Project
parent 788b8aa29d
commit e1325cf26e
3 changed files with 35 additions and 34 deletions

View File

@ -95,10 +95,9 @@ void QOpenGLTextureCacheWrapper::cleanupTexturesForPixmapData(QPlatformPixmap *p
cleanupTexturesForCacheKey(pmd->cacheKey());
}
QOpenGLTextureCache::QOpenGLTextureCache(QOpenGLContext *ctx, bool useByteSwapImage)
QOpenGLTextureCache::QOpenGLTextureCache(QOpenGLContext *ctx)
: QOpenGLSharedResource(ctx->shareGroup())
, m_cache(64 * 1024) // 64 MB cache
, m_useByteSwapImage(useByteSwapImage)
{
}
@ -152,38 +151,13 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
return id;
}
static inline void qgl_byteSwapImage(QImage &img)
{
const int width = img.width();
const int height = img.height();
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
{
for (int i = 0; i < height; ++i) {
uint *p = (uint *) img.scanLine(i);
for (int x = 0; x < width; ++x)
p[x] = ((p[x] << 16) & 0xff0000) | ((p[x] >> 16) & 0xff) | (p[x] & 0xff00ff00);
}
} else {
for (int i = 0; i < height; ++i) {
uint *p = (uint *) img.scanLine(i);
for (int x = 0; x < width; ++x)
p[x] = (p[x] << 8) | (p[x] >> 24);
}
}
}
GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image)
{
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
QImage tx = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
// Performance could be improved by skipping qgl_byteSwapImage().
if (m_useByteSwapImage)
qgl_byteSwapImage(tx);
QImage tx = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx.width(), tx.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, const_cast<const QImage &>(tx).bits());

View File

@ -78,7 +78,7 @@ class Q_GUI_EXPORT QOpenGLTextureCache : public QOpenGLSharedResource
public:
static QOpenGLTextureCache *cacheForContext(QOpenGLContext *context);
QOpenGLTextureCache(QOpenGLContext *, bool useByteSwapImage = true);
QOpenGLTextureCache(QOpenGLContext *);
~QOpenGLTextureCache();
GLuint bindTexture(QOpenGLContext *context, const QPixmap &pixmap);
@ -94,7 +94,6 @@ private:
QMutex m_mutex;
QCache<quint64, QOpenGLCachedTexture> m_cache;
bool m_useByteSwapImage;
};
QT_END_NAMESPACE

View File

@ -2308,10 +2308,18 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
QImage::Format target_format = img.format();
bool premul = options & QGLContext::PremultipliedAlphaBindOption;
bool needsbyteswap = true;
GLenum externalFormat;
GLuint pixel_type;
if (qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat)) {
if (target_format == QImage::Format_RGBA8888
|| target_format == QImage::Format_RGBA8888_Premultiplied
|| target_format == QImage::Format_RGBX8888) {
externalFormat = GL_RGBA;
pixel_type = GL_UNSIGNED_BYTE;
needsbyteswap = false;
} else if (qgl_extensions()->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat)) {
externalFormat = GL_BGRA;
needsbyteswap = false;
if (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_2)
pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
else
@ -2335,6 +2343,22 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
img = img.convertToFormat(target_format = QImage::Format_ARGB32);
#ifdef QGL_BIND_TEXTURE_DEBUG
printf(" - converted ARGB32_Premultiplied -> ARGB32 (%d ms)\n", time.elapsed());
#endif
}
break;
case QImage::Format_RGBA8888:
if (premul) {
img = img.convertToFormat(target_format = QImage::Format_RGBA8888_Premultiplied);
#ifdef QGL_BIND_TEXTURE_DEBUG
printf(" - converted RGBA8888 -> RGBA8888_Premultiplied (%d ms) \n", time.elapsed());
#endif
}
break;
case QImage::Format_RGBA8888_Premultiplied:
if (!premul) {
img = img.convertToFormat(target_format = QImage::Format_RGBA8888);
#ifdef QGL_BIND_TEXTURE_DEBUG
printf(" - converted RGBA8888_Premultiplied -> RGBA8888 (%d ms) \n", time.elapsed());
#endif
}
break;
@ -2342,10 +2366,14 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
pixel_type = GL_UNSIGNED_SHORT_5_6_5;
externalFormat = GL_RGB;
internalFormat = GL_RGB;
needsbyteswap = false;
break;
case QImage::Format_RGB32:
case QImage::Format_RGBX8888:
break;
default:
// Ideally more formats would be converted directly to an RGBA8888 format,
// but we are only guaranteed to have a fast conversion to an ARGB format.
if (img.hasAlphaChannel()) {
img = img.convertToFormat(premul
? QImage::Format_ARGB32_Premultiplied
@ -2383,10 +2411,10 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G
#endif
}
if (externalFormat == GL_RGBA) {
if (needsbyteswap) {
// The only case where we end up with a depth different from
// 32 in the switch above is for the RGB16 case, where we set
// the format to GL_RGB
// 32 in the switch above is for the RGB16 case, where we do
// not need a byteswap.
Q_ASSERT(img.depth() == 32);
qgl_byteSwapImage(img, pixel_type);
#ifdef QGL_BIND_TEXTURE_DEBUG