Optimize OpenGL binding of ARGB32PM backing store

Detect premultiplied backing store and upload it without conversion
and adjust blend to not multiply alpha again.

Task-number: QTBUG-50381
Change-Id: I51939c4f82fbb0c48eaca6e2475bf4cf3722bc2d
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
This commit is contained in:
Allan Sandfeld Jensen 2016-01-11 11:32:44 +01:00
parent 18119a58de
commit 0bc4288689
4 changed files with 60 additions and 19 deletions

View File

@ -64,7 +64,7 @@ QT_BEGIN_NAMESPACE
bound texture, otherwise returns false.
*/
bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer,
bool *swizzle,
bool *swizzle, bool *premultiplied,
const QRect &rect)
{
if (graphicsBuffer->lock(QPlatformGraphicsBuffer::TextureAccess)) {
@ -74,8 +74,10 @@ bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer
}
if (swizzle)
*swizzle = false;
if (premultiplied)
*premultiplied = false;
} else if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
if (!bindSWToTexture(graphicsBuffer, swizzle, rect)) {
if (!bindSWToTexture(graphicsBuffer, swizzle, premultiplied, rect)) {
qWarning("Failed to bind %sgraphicsbuffer to texture", "SW ");
return false;
}
@ -109,7 +111,7 @@ bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer
Returns true on success, otherwise false.
*/
bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer,
bool *swizzleRandB,
bool *swizzleRandB, bool *premultipliedB,
const QRect &subRect)
{
#ifndef QT_NO_OPENGL
@ -124,14 +126,30 @@ bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffe
Q_ASSERT(subRect.isEmpty() || QRect(QPoint(0,0), size).contains(subRect));
bool swizzle = false;
bool premultiplied = false;
QImage::Format imageformat = QImage::toImageFormat(graphicsBuffer->format());
QImage image(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), imageformat);
if (graphicsBuffer->bytesPerLine() != (size.width() * 4)) {
image = image.convertToFormat(QImage::Format_RGBA8888);
} else if (imageformat == QImage::Format_RGB32) {
swizzle = true;
} else if (imageformat != QImage::Format_RGBA8888) {
image = image.convertToFormat(QImage::Format_RGBA8888);
} else {
switch (imageformat) {
case QImage::Format_ARGB32_Premultiplied:
premultiplied = true;
// no break
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
swizzle = true;
break;
case QImage::Format_RGBA8888_Premultiplied:
premultiplied = true;
// no break
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
break;
default:
image = image.convertToFormat(QImage::Format_RGBA8888);
break;
}
}
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
@ -170,6 +188,8 @@ bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffe
}
if (swizzleRandB)
*swizzleRandB = swizzle;
if (premultipliedB)
*premultipliedB = premultiplied;
return true;

View File

@ -39,8 +39,8 @@
QT_BEGIN_NAMESPACE
namespace QPlatformGraphicsBufferHelper {
bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, const QRect &rect = QRect());
bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB = Q_NULLPTR, const QRect &rect = QRect());
bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, bool *premultipliedB, const QRect &rect = QRect());
bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB = Q_NULLPTR, bool *premultipliedB = Q_NULLPTR, const QRect &rect = QRect());
}
QT_END_NAMESPACE

View File

@ -92,6 +92,7 @@ public:
mutable GLuint textureId;
mutable QSize textureSize;
mutable bool needsSwizzle;
mutable bool premultiplied;
QOpenGLTextureBlitter *blitter;
#endif
};
@ -323,9 +324,6 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
blitTextureForWidget(textures, i, window, deviceWindowRect, d_ptr->blitter, offset);
}
funcs->glEnable(GL_BLEND);
funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
// Backingstore texture with the normal widgets.
GLuint textureId = 0;
QOpenGLTextureBlitter::Origin origin = QOpenGLTextureBlitter::OriginTopLeft;
@ -345,7 +343,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle)) {
if (QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied)) {
d_ptr->textureSize = graphicsBuffer->size();
} else {
d_ptr->textureSize = QSize(0,0);
@ -354,7 +352,7 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
graphicsBuffer->unlock();
} else if (!region.isEmpty()){
funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle);
QPlatformGraphicsBufferHelper::lockAndBindToTexture(graphicsBuffer, &d_ptr->needsSwizzle, &d_ptr->premultiplied);
}
if (graphicsBuffer->origin() == QPlatformGraphicsBuffer::OriginBottomLeft)
@ -364,10 +362,17 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
TextureFlags flags = 0;
textureId = toTexture(deviceRegion(region, window, offset), &d_ptr->textureSize, &flags);
d_ptr->needsSwizzle = (flags & TextureSwizzle) != 0;
d_ptr->premultiplied = (flags & TexturePremultiplied) != 0;
if (flags & TextureFlip)
origin = QOpenGLTextureBlitter::OriginBottomLeft;
}
funcs->glEnable(GL_BLEND);
if (d_ptr->premultiplied)
funcs->glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
else
funcs->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
if (textureId) {
if (d_ptr->needsSwizzle)
d_ptr->blitter->setSwizzleRB(true);
@ -443,10 +448,26 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu
QImage image = toImage();
QSize imageSize = image.size();
bool needConvert = false;
*flags = 0;
if (image.format() == QImage::Format_RGB32)
switch (image.format()) {
case QImage::Format_ARGB32_Premultiplied:
*flags |= TexturePremultiplied;
// no break
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
*flags |= TextureSwizzle;
break;
case QImage::Format_RGBA8888_Premultiplied:
*flags |= TexturePremultiplied;
// no break
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
break;
default:
needConvert = true;
break;
}
if (imageSize.isEmpty()) {
*textureSize = imageSize;
return 0;
@ -460,8 +481,7 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu
*textureSize = imageSize;
// Fast path for RGB32 and RGBA8888, convert everything else to RGBA8888.
if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_RGBA8888)
if (needConvert)
image = image.convertToFormat(QImage::Format_RGBA8888);
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();

View File

@ -118,7 +118,8 @@ public:
virtual QImage toImage() const;
enum TextureFlag {
TextureSwizzle = 0x01,
TextureFlip = 0x02
TextureFlip = 0x02,
TexturePremultiplied = 0x04,
};
Q_DECLARE_FLAGS(TextureFlags, TextureFlag)
virtual GLuint toTexture(const QRegion &dirtyRegion, QSize *textureSize, TextureFlags *flags) const;