Update only dirty areas in kms backingstore
authorLaszlo Agocs <laszlo.p.agocs@nokia.com>
Wed, 25 Jul 2012 08:52:07 +0000 (11:52 +0300)
committerQt by Nokia <qt-info@nokia.com>
Wed, 25 Jul 2012 12:50:16 +0000 (14:50 +0200)
Do not upload the entire (typically fullscreen) image
all the time.

Taken from eglfs' backingstore implementation.

Change-Id: I53db5cf54577ebea715d6cbd7215b9d2154e8960
Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com>
src/plugins/platforms/kms/qkmsbackingstore.cpp
src/plugins/platforms/kms/qkmsbackingstore.h

index 9fb828a..15f436b 100644 (file)
@@ -73,8 +73,9 @@ QPaintDevice *QKmsBackingStore::paintDevice()
     return &m_image;
 }
 
-void QKmsBackingStore::beginPaint(const QRegion &)
+void QKmsBackingStore::beginPaint(const QRegion &rgn)
 {
+    m_dirty |= rgn;
 }
 
 void QKmsBackingStore::endPaint()
@@ -146,8 +147,39 @@ void QKmsBackingStore::flush(QWindow *window, const QRegion &region, const QPoin
 
     glBindTexture(GL_TEXTURE_2D, m_texture);
 
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(),
-                 0, GL_RGBA, GL_UNSIGNED_BYTE, m_image.constScanLine(0));
+    if (!m_dirty.isNull()) {
+        QRect imageRect = m_image.rect();
+        QRegion fixed;
+        Q_FOREACH (const QRect &rect, m_dirty.rects()) {
+            // intersect with image rect to be sure
+            QRect r = imageRect & rect;
+            // 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());
+            }
+            fixed |= r;
+        }
+
+        Q_FOREACH (const QRect &rect, fixed.rects()) {
+            // 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
+            if (rect.width() == imageRect.width()) {
+                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(),
+                                rect.width(), rect.height(),
+                                GL_RGBA, GL_UNSIGNED_BYTE,
+                                m_image.constScanLine(rect.y()));
+            } else {
+                glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(),
+                                rect.width(), rect.height(),
+                                GL_RGBA, GL_UNSIGNED_BYTE,
+                                m_image.copy(rect).constBits());
+            }
+        }
+
+        m_dirty = QRegion();
+    }
 
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
index 6357019..e9d103b 100644 (file)
@@ -69,6 +69,7 @@ private:
     QImage m_image;
     uint m_texture;
     QOpenGLShaderProgram *m_program;
+    QRegion m_dirty;
 };
 
 QT_END_NAMESPACE