Implemented raster based backing store for EGLFS plugin.
authorSamuel Rødal <samuel.rodal@nokia.com>
Mon, 16 Apr 2012 19:24:41 +0000 (21:24 +0200)
committerQt by Nokia <qt-info@nokia.com>
Mon, 16 Apr 2012 19:42:19 +0000 (21:42 +0200)
This improves quality of rendering for QWidget-based applications a bit.

Change-Id: I6b832d1de7e722f4dbe4e82882f5db35f0b8c30c
Reviewed-by: Girish Ramakrishnan <girish.1.ramakrishnan@nokia.com>
src/plugins/platforms/eglfs/qeglfsbackingstore.cpp
src/plugins/platforms/eglfs/qeglfsbackingstore.h

index 8e9e5f7..48ac680 100644 (file)
 
 #include <QtGui/QOpenGLContext>
 #include <QtGui/QOpenGLPaintDevice>
+#include <QtGui/QOpenGLShaderProgram>
+
+#include <QtGui/QScreen>
 
 QT_BEGIN_NAMESPACE
 
 QEglFSBackingStore::QEglFSBackingStore(QWindow *window)
     : QPlatformBackingStore(window)
     , m_context(new QOpenGLContext)
+#ifdef EGLFS_BACKINGSTORE_USE_IMAGE
+    , m_texture(0)
+    , m_program(0)
+#endif
 {
     m_context->setFormat(window->requestedFormat());
     m_context->setScreen(window->screen());
@@ -62,7 +69,11 @@ QEglFSBackingStore::~QEglFSBackingStore()
 
 QPaintDevice *QEglFSBackingStore::paintDevice()
 {
+#ifdef EGLFS_BACKINGSTORE_USE_IMAGE
+    return &m_image;
+#else
     return m_device;
+#endif
 }
 
 void QEglFSBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
@@ -74,27 +85,135 @@ void QEglFSBackingStore::flush(QWindow *window, const QRegion &region, const QPo
     qWarning("QEglBackingStore::flush %p", window);
 #endif
 
+#ifdef EGLFS_BACKINGSTORE_USE_IMAGE
+    if (!m_program) {
+        static const char *textureVertexProgram =
+            "attribute highp vec2 vertexCoordEntry;\n"
+            "attribute highp vec2 textureCoordEntry;\n"
+            "varying highp vec2 textureCoord;\n"
+            "void main() {\n"
+            "   textureCoord = textureCoordEntry;\n"
+            "   gl_Position = vec4(vertexCoordEntry, 0.0, 1.0);\n"
+            "}\n";
+
+        static const char *textureFragmentProgram =
+            "uniform sampler2D texture;\n"
+            "varying highp vec2 textureCoord;\n"
+            "void main() {\n"
+            "   gl_FragColor = texture2D(texture, textureCoord);\n"
+            "}\n";
+
+        m_program = new QOpenGLShaderProgram;
+
+        m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram);
+        m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram);
+        m_program->link();
+
+        m_vertexCoordEntry = m_program->attributeLocation("vertexCoordEntry");
+        m_textureCoordEntry = m_program->attributeLocation("textureCoordEntry");
+    }
+
+    m_program->bind();
+
+    const GLfloat textureCoordinates[] = {
+        0, 1,
+        1, 1,
+        1, 0,
+        0, 0
+    };
+
+    QRectF r = window->geometry();
+    QRectF sr = window->screen()->geometry();
+
+    GLfloat x1 = (r.left() / sr.width()) * 2 - 1;
+    GLfloat x2 = (r.right() / sr.width()) * 2 - 1;
+    GLfloat y1 = (r.top() / sr.height()) * 2 - 1;
+    GLfloat y2 = (r.bottom() / sr.height()) * 2 - 1;
+
+    const GLfloat vertexCoordinates[] = {
+        x1, y1,
+        x2, y1,
+        x2, y2,
+        x1, y2
+    };
+
+    glEnableVertexAttribArray(m_vertexCoordEntry);
+    glEnableVertexAttribArray(m_textureCoordEntry);
+
+    glVertexAttribPointer(m_vertexCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinates);
+    glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
+
+    glBindTexture(GL_TEXTURE_2D, m_texture);
+
+    foreach (const QRect &rect, m_dirty.rects()) {
+        if (rect == m_image.rect()) {
+            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE, m_image.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());
+        }
+    }
+
+    m_dirty = QRegion();
+
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    glDisableVertexAttribArray(m_vertexCoordEntry);
+    glDisableVertexAttribArray(m_textureCoordEntry);
+#endif
+
     m_context->swapBuffers(window);
 }
 
-void QEglFSBackingStore::beginPaint(const QRegion &)
+void QEglFSBackingStore::makeCurrent()
 {
     // needed to prevent QOpenGLContext::makeCurrent() from failing
     window()->setSurfaceType(QSurface::OpenGLSurface);
 
     m_context->makeCurrent(window());
+}
+
+void QEglFSBackingStore::beginPaint(const QRegion &rgn)
+{
+    makeCurrent();
+
+#ifdef EGLFS_BACKINGSTORE_USE_IMAGE
+    m_dirty = m_dirty | rgn;
+#else
+    Q_UNUSED(rgn);
     m_device = new QOpenGLPaintDevice(window()->size());
+#endif
 }
 
 void QEglFSBackingStore::endPaint()
 {
+#ifndef EGLFS_BACKINGSTORE_USE_IMAGE
     delete m_device;
+#endif
 }
 
 void QEglFSBackingStore::resize(const QSize &size, const QRegion &staticContents)
 {
-    Q_UNUSED(size);
     Q_UNUSED(staticContents);
+
+#ifdef EGLFS_BACKINGSTORE_USE_IMAGE
+    m_image = QImage(size, QImage::Format_RGB32);
+    makeCurrent();
+    if (m_texture)
+        glDeleteTextures(1, &m_texture);
+    glGenTextures(1, &m_texture);
+    glBindTexture(GL_TEXTURE_2D, m_texture);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+#else
+    Q_UNUSED(size);
+#endif
 }
 
 QT_END_NAMESPACE
index 97ea322..f723bca 100644 (file)
 
 #include <QtGui/qplatformbackingstore_qpa.h>
 
+#include <QImage>
+#include <QRegion>
+
+#define EGLFS_BACKINGSTORE_USE_IMAGE
+
 QT_BEGIN_NAMESPACE
 
 class QOpenGLContext;
 class QOpenGLPaintDevice;
+class QOpenGLShaderProgram;
 
 class QEglFSBackingStore : public QPlatformBackingStore
 {
@@ -64,8 +70,19 @@ public:
     void resize(const QSize &size, const QRegion &staticContents);
 
 private:
+    void makeCurrent();
+
     QOpenGLContext *m_context;
+#ifdef EGLFS_BACKINGSTORE_USE_IMAGE
+    QImage m_image;
+    uint m_texture;
+    QRegion m_dirty;
+    QOpenGLShaderProgram *m_program;
+    int m_vertexCoordEntry;
+    int m_textureCoordEntry;
+#else
     QOpenGLPaintDevice *m_device;
+#endif
 };
 
 QT_END_NAMESPACE