Avoid image copy in toTexture() on GLES 3.0 as well

The default backingstore implementation is now cleaned for ES_2 ifdefs.
All the checks are now done at runtime and ES 3.0+ is included as well
for the efficient, QImage::copy()-less path.

For embedded a customized backingstore is used so the change has to be
done separately there.

This should result in a slight improvement for QOpenGLWidget/QQuickWidget
when running on GLES 3.x.

Task-number: QTBUG-37624
Change-Id: I107330c25a993c5cdcd92e4ebdc17ae172a03da8
Reviewed-by: Paul Olav Tvete <paul.tvete@theqtcompany.com>
This commit is contained in:
Laszlo Agocs 2015-09-15 15:51:43 +02:00
parent 2811216973
commit 715a8e6f4e
2 changed files with 51 additions and 32 deletions

View File

@ -48,6 +48,16 @@
#include <qpa/qplatformgraphicsbuffer.h> #include <qpa/qplatformgraphicsbuffer.h>
#include <qpa/qplatformgraphicsbufferhelper.h> #include <qpa/qplatformgraphicsbufferhelper.h>
#ifndef GL_TEXTURE_BASE_LEVEL
#define GL_TEXTURE_BASE_LEVEL 0x813C
#endif
#ifndef GL_TEXTURE_MAX_LEVEL
#define GL_TEXTURE_MAX_LEVEL 0x813D
#endif
#ifndef GL_UNPACK_ROW_LENGTH
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QPlatformBackingStorePrivate class QPlatformBackingStorePrivate
@ -311,12 +321,11 @@ void QPlatformBackingStore::composeAndFlush(QWindow *window, const QRegion &regi
funcs->glDeleteTextures(1, &d_ptr->textureId); funcs->glDeleteTextures(1, &d_ptr->textureId);
funcs->glGenTextures(1, &d_ptr->textureId); funcs->glGenTextures(1, &d_ptr->textureId);
funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
#ifndef QT_OPENGL_ES_2 QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!QOpenGLContext::currentContext()->isOpenGLES()) { if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
} }
#endif
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -435,18 +444,16 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu
image = image.convertToFormat(QImage::Format_RGBA8888); image = image.convertToFormat(QImage::Format_RGBA8888);
QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
if (resized) { if (resized) {
if (d_ptr->textureId) if (d_ptr->textureId)
funcs->glDeleteTextures(1, &d_ptr->textureId); funcs->glDeleteTextures(1, &d_ptr->textureId);
funcs->glGenTextures(1, &d_ptr->textureId); funcs->glGenTextures(1, &d_ptr->textureId);
funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId); funcs->glBindTexture(GL_TEXTURE_2D, d_ptr->textureId);
#ifndef QT_OPENGL_ES_2 QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!QOpenGLContext::currentContext()->isOpenGLES()) { if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
} }
#endif
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -459,15 +466,13 @@ GLuint QPlatformBackingStore::toTexture(const QRegion &dirtyRegion, QSize *textu
QRect imageRect = image.rect(); QRect imageRect = image.rect();
QRect rect = dirtyRegion.boundingRect() & imageRect; QRect rect = dirtyRegion.boundingRect() & imageRect;
#ifndef QT_OPENGL_ES_2 QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!QOpenGLContext::currentContext()->isOpenGLES()) { if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width()); funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, image.width());
funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
image.constScanLine(rect.y()) + rect.x() * 4); image.constScanLine(rect.y()) + rect.x() * 4);
funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
} else } else {
#endif
{
// if the rect is wide enough it's cheaper to just // if the rect is wide enough it's cheaper to just
// extend it instead of doing an image copy // extend it instead of doing an image copy
if (rect.width() >= imageRect.width() / 2) { if (rect.width() >= imageRect.width() / 2) {

View File

@ -39,6 +39,10 @@
#include "qopenglcompositorbackingstore_p.h" #include "qopenglcompositorbackingstore_p.h"
#include "qopenglcompositor_p.h" #include "qopenglcompositor_p.h"
#ifndef GL_UNPACK_ROW_LENGTH
#define GL_UNPACK_ROW_LENGTH 0x0CF2
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
/*! /*!
@ -100,29 +104,39 @@ void QOpenGLCompositorBackingStore::updateTexture()
QRegion fixed; QRegion fixed;
QRect imageRect = m_image.rect(); QRect imageRect = m_image.rect();
foreach (const QRect &rect, m_dirty.rects()) { QOpenGLContext *ctx = QOpenGLContext::currentContext();
// intersect with image rect to be sure if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
QRect r = imageRect & rect; foreach (const QRect &rect, m_dirty.rects()) {
QRect r = imageRect & rect;
// if the rect is wide enough it's cheaper to just glPixelStorei(GL_UNPACK_ROW_LENGTH, m_image.width());
// extend it instead of doing an image copy glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE,
if (r.width() >= imageRect.width() / 2) { m_image.constScanLine(r.y()) + r.x() * 4);
r.setX(0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
r.setWidth(imageRect.width());
} }
} else {
foreach (const QRect &rect, m_dirty.rects()) {
// intersect with image rect to be sure
QRect r = imageRect & rect;
fixed |= r; // if the rect is wide enough it's cheaper to just
} // extend it instead of doing an image copy
if (r.width() >= imageRect.width() / 2) {
r.setX(0);
r.setWidth(imageRect.width());
}
foreach (const QRect &rect, fixed.rects()) { fixed |= r;
// if the sub-rect is full-width we can pass the image data directly to }
// OpenGL instead of copying, since there's no gap between scanlines foreach (const QRect &rect, fixed.rects()) {
if (rect.width() == imageRect.width()) { // if the sub-rect is full-width we can pass the image data directly to
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, // OpenGL instead of copying, since there's no gap between scanlines
m_image.constScanLine(rect.y())); if (rect.width() == imageRect.width()) {
} else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_image.constScanLine(rect.y()));
m_image.copy(rect).constBits()); } else {
glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
m_image.copy(rect).constBits());
}
} }
} }